### Initialize and Start Project Source: https://github.com/deepgram-starters/php-live-text-to-speech/blob/main/AGENTS.md Commands to clone submodules, install dependencies, and launch the development servers. ```bash # Initialize (clone submodules + install deps) make init # Set up environment test -f .env || cp sample.env .env # then set DEEPGRAM_API_KEY # Start both servers make start # Backend: http://localhost:8081 # Frontend: http://localhost:8080 ``` -------------------------------- ### Install Dependencies Source: https://github.com/deepgram-starters/php-live-text-to-speech/blob/main/AGENTS.md Commands to install backend and frontend dependencies. ```bash composer install ``` ```bash cd frontend && corepack pnpm install ``` -------------------------------- ### Initialize and Start PHP App Source: https://github.com/deepgram-starters/php-live-text-to-speech/blob/main/README.md Use the Makefile to initialize the project dependencies, set up your Deepgram API key in the .env file, and start the local development server. ```bash make init cp sample.env .env # Add your DEEPGRAM_API_KEY make start ``` -------------------------------- ### Initialize and Run Application Source: https://context7.com/deepgram-starters/php-live-text-to-speech/llms.txt Use these commands to prepare the environment and start the backend and frontend services. ```bash # Check prerequisites (git, php, composer, pnpm) make check-prereqs # Initialize submodules and install all dependencies make init # Configure environment cp sample.env .env # Edit .env and add your DEEPGRAM_API_KEY # Start both backend (port 8081) and frontend (port 8080) make start ``` -------------------------------- ### Manage Server Lifecycle Source: https://github.com/deepgram-starters/php-live-text-to-speech/blob/main/AGENTS.md Commands for starting, stopping, and rebuilding the application environment. ```bash make start ``` ```bash # Terminal 1 — Backend php server.php # Terminal 2 — Frontend cd frontend && corepack pnpm run dev -- --port 8080 --no-open ``` ```bash lsof -ti:8080,8081 | xargs kill -9 2>/dev/null ``` ```bash rm -rf vendor frontend/node_modules frontend/.vite make init ``` -------------------------------- ### Get Project Metadata Source: https://context7.com/deepgram-starters/php-live-text-to-speech/llms.txt Fetch project details and configuration metadata from the /api/metadata endpoint. ```bash # Fetch project metadata curl -s http://localhost:8081/api/metadata | python3 -m json.tool # Response: # { # "title": "PHP Live Text-to-Speech", # "description": "Get started using Deepgram's Live Text-to-Speech with this PHP demo app", # "author": "Deepgram DX Team (https://developers.deepgram.com)", # "repository": "https://github.com/deepgram-starters/php-live-text-to-speech", # "useCase": "live-text-to-speech", # "language": "php", # "framework": "php", # "sdk": "N/A", # "tags": ["live-text-to-speech", "live-tts", "streaming-tts", "real-time-tts", "streaming-text-to-speech", "php", "ratchet"] # } ``` -------------------------------- ### Build and Run Docker Container Source: https://context7.com/deepgram-starters/php-live-text-to-speech/llms.txt Commands to build the Docker image and run the container, including setting environment variables and exposing ports. Also includes an example for deploying to Fly.io. ```bash # Build and run Docker container docker build -f deploy/Dockerfile -t php-live-tts . docker run -p 8080:8080 -e DEEPGRAM_API_KEY=your_key php-live-tts # Or deploy to Fly.io fly deploy ``` -------------------------------- ### Dockerfile for PHP Live Text-to-Speech Deployment Source: https://context7.com/deepgram-starters/php-live-text-to-speech/llms.txt A Dockerfile to build a production-ready image for the PHP Live Text-to-Speech application. It installs dependencies, copies the application, and configures Caddy and Supervisor. ```dockerfile # deploy/Dockerfile FROM php:8.3-cli-alpine # Install dependencies RUN apk add --no-cache caddy supervisor # Copy application WORKDIR /app COPY . . # Install PHP dependencies RUN composer install --no-dev --optimize-autoloader # Caddy configuration for reverse proxy COPY deploy/Caddyfile /etc/caddy/Caddyfile # Start with supervisor CMD ["supervisord", "-c", "/etc/supervisor/supervisord.conf"] ``` -------------------------------- ### GET /api/metadata - Get Project Metadata Source: https://context7.com/deepgram-starters/php-live-text-to-speech/llms.txt This endpoint retrieves project metadata, including title, description, use case, language, and tags, as defined in the `deepgram.toml` configuration file. ```APIDOC ## GET /api/metadata - Get Project Metadata ### Description Returns project metadata from `deepgram.toml` including title, description, use case, language, and tags. ### Method GET ### Endpoint /api/metadata ### Parameters None ### Request Example None ### Response #### Success Response (200) - **title** (string) - The title of the project. - **description** (string) - A description of the project. - **author** (string) - The author of the project. - **repository** (string) - The URL of the project repository. - **useCase** (string) - The primary use case of the project. - **language** (string) - The programming language used. - **framework** (string) - The framework used. - **sdk** (string) - The SDK used (if any). - **tags** (array of strings) - Tags associated with the project. #### Response Example ```json { "title": "PHP Live Text-to-Speech", "description": "Get started using Deepgram's Live Text-to-Speech with this PHP demo app", "author": "Deepgram DX Team (https://developers.deepgram.com)", "repository": "https://github.com/deepgram-starters/php-live-text-to-speech", "useCase": "live-text-to-speech", "language": "php", "framework": "php", "sdk": "N/A", "tags": ["live-text-to-speech", "live-tts", "streaming-tts", "real-time-tts", "streaming-text-to-speech", "php", "ratchet"] } ``` ``` -------------------------------- ### Conventional Commits Examples Source: https://github.com/deepgram-starters/php-live-text-to-speech/blob/main/AGENTS.md Standardized commit message formats for the project. Do not include Co-Authored-By lines for Claude. ```text feat(php-live-text-to-speech): add diarization support fix(php-live-text-to-speech): resolve WebSocket close handling refactor(php-live-text-to-speech): simplify session endpoint chore(deps): update frontend submodule ``` -------------------------------- ### GET /health - Health Check Source: https://context7.com/deepgram-starters/php-live-text-to-speech/llms.txt This endpoint provides a health check for the server, returning a status of 'ok' for monitoring and load balancer purposes. ```APIDOC ## GET /health - Health Check ### Description Returns server health status for monitoring and load balancer health checks. ### Method GET ### Endpoint /health ### Parameters None ### Request Example None ### Response #### Success Response (200) - **status** (string) - The health status of the server, typically "ok". #### Response Example ```json { "status": "ok" } ``` ``` -------------------------------- ### GET /api/session - Issue JWT Session Token Source: https://context7.com/deepgram-starters/php-live-text-to-speech/llms.txt This endpoint issues a signed JWT token for authenticating WebSocket connections. The token is valid for 1 hour and must be passed via the `access_token.` WebSocket subprotocol. ```APIDOC ## GET /api/session - Issue JWT Session Token ### Description Returns a signed JWT token for authenticating WebSocket connections. The token is valid for 1 hour and must be passed via the `access_token.` WebSocket subprotocol. ### Method GET ### Endpoint /api/session ### Parameters None ### Request Example None ### Response #### Success Response (200) - **token** (string) - The signed JWT token. #### Response Example ```json { "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE3MDk4MjE0MDAsImV4cCI6MTcwOTgyNTAwMH0.abc123..." } ``` ``` -------------------------------- ### Configure Environment Variables Source: https://context7.com/deepgram-starters/php-live-text-to-speech/llms.txt Define required and optional settings in the .env file to configure the server. ```bash # Required - Your Deepgram API key from https://console.deepgram.com DEEPGRAM_API_KEY=your_api_key_here # Optional - Backend server port (default: 8081) PORT=8081 # Optional - Server bind address (default: 0.0.0.0) HOST=0.0.0.0 # Optional - JWT signing secret for production (generates random secret if not set) SESSION_SECRET=your_production_secret_here ``` -------------------------------- ### Makefile Commands for Project Management Source: https://context7.com/deepgram-starters/php-live-text-to-speech/llms.txt A collection of Makefile commands for setting up, developing, testing, and maintaining the project. These commands streamline common development workflows. ```bash # Setup commands make check-prereqs # Verify git, php, composer, pnpm are installed make init # Initialize submodules + install all dependencies make install # Install backend and frontend dependencies make install-backend # Install only composer dependencies make install-frontend # Install only frontend npm packages # Development commands make start # Start backend (8081) and frontend (8080) in parallel make start-backend # Start only the PHP API server make start-frontend # Start only the Vite frontend server make test # Run contract conformance tests # Maintenance commands make update # Update git submodules to latest make clean # Remove vendor/, node_modules/, dist/ make status # Show git and submodule status make eject-frontend # Convert frontend submodule to regular directory ``` -------------------------------- ### Testing and Endpoint Verification Source: https://github.com/deepgram-starters/php-live-text-to-speech/blob/main/AGENTS.md Commands to execute conformance tests and manually verify the metadata and session API endpoints. ```bash # Run conformance tests (requires app to be running) make test # Manual endpoint check curl -sf http://localhost:8081/api/metadata | python3 -m json.tool curl -sf http://localhost:8081/api/session | python3 -m json.tool ``` -------------------------------- ### PHP Server Implementation Source: https://context7.com/deepgram-starters/php-live-text-to-speech/llms.txt The main server implementation uses Ratchet for WebSocket handling with ReactPHP for asynchronous I/O. This class acts as a proxy, forwarding messages between the client and Deepgram's TTS API. ```APIDOC ## PHP Server Implementation The main server implementation uses Ratchet for WebSocket handling with ReactPHP for async I/O. ### Class: LiveTextToSpeechProxy Implements `MessageComponentInterface` to handle WebSocket connections. #### Constructor - **__construct**(string $apiKey) Initializes the proxy with a Deepgram API key. #### Methods - **onOpen**(ConnectionInterface $conn): void Called when a new WebSocket connection is opened. - Validates JWT from the `Sec-WebSocket-Protocol` header. - Parses query parameters from the connection URI. - Constructs the Deepgram TTS WebSocket URL with provided parameters. - Establishes a connection to the Deepgram API. - Sets up bidirectional message forwarding between the client and Deepgram. - **onMessage**(ConnectionInterface $from, $msg): void Called when a message is received from a client. - Forwards the message to the corresponding Deepgram WebSocket connection. - **onClose**(ConnectionInterface $conn): void Called when a WebSocket connection is closed. - Closes the associated Deepgram connection and cleans up resources. - **onError**(ConnectionInterface $conn, Exception $e): void Called when an error occurs on a WebSocket connection. - Closes the connection. ### Server Setup ```php clients = new \SplObjectStorage(); $this->apiKey = $apiKey; } public function onOpen(ConnectionInterface $conn): void { // Validate JWT from access_token.* subprotocol $protocolHeader = $conn->httpRequest->getHeaderLine('Sec-WebSocket-Protocol'); if (!$this->validateToken($protocolHeader)) { $conn->close(); return; } // Parse query params and connect to Deepgram $query = $conn->httpRequest->getUri()->getQuery(); parse_str($query, $params); $dgUrl = $this->deepgramUrl . '?' . http_build_query([ 'model' => $params['model'] ?? 'aura-asteria-en', 'encoding' => $params['encoding'] ?? 'linear16', 'sample_rate' => $params['sample_rate'] ?? '48000', 'container' => $params['container'] ?? 'none', ]); // Connect to Deepgram and set up bidirectional forwarding $connector = new \Ratchet\Client\Connector(Loop::get()); $connector($dgUrl, [], ['Authorization' => 'Token ' . $this->apiKey]) ->then(function ($deepgramWs) use ($conn) { $this->clients[$conn] = $deepgramWs; // Forward Deepgram responses to client $deepgramWs->on('message', fn($msg) => $conn->send($msg->getPayload())); $deepgramWs->on('close', fn() => $conn->close()); }); } public function onMessage(ConnectionInterface $from, $msg): void { // Forward client messages to Deepgram if ($this->clients->contains($from) && $this->clients[$from]) { $this->clients[$from]->send($msg); } } public function onClose(ConnectionInterface $conn): void { if ($this->clients->contains($conn)) { $this->clients[$conn]?->close(); $this->clients->detach($conn); } } public function onError(ConnectionInterface $conn, \Exception $e): void { $conn->close(); } // Placeholder for token validation logic private function validateToken(string $protocolHeader): bool { // Implement your JWT validation here return true; // Placeholder } } // Start server $apiKey = 'YOUR_DEEPGRAM_API_KEY'; // Replace with your actual API key $server = IoServer::factory( new HttpServer(new WsServer(new LiveTextToSpeechProxy($apiKey))), 8081, '0.0.0.0' ); $server->run(); ``` ``` -------------------------------- ### PHP Live Text-to-Speech Proxy Server Source: https://context7.com/deepgram-starters/php-live-text-to-speech/llms.txt Implement a WebSocket proxy server in PHP using Ratchet and ReactPHP. This server handles client connections, validates JWT tokens, parses query parameters, and forwards messages bidirectionally between clients and Deepgram's TTS API. ```php clients = new SplObjectStorage(); $this->apiKey = $apiKey; } public function onOpen(ConnectionInterface $conn): void { // Validate JWT from access_token.* subprotocol $protocolHeader = $conn->httpRequest->getHeaderLine('Sec-WebSocket-Protocol'); if (!$this->validateToken($protocolHeader)) { $conn->close(); return; } // Parse query params and connect to Deepgram $query = $conn->httpRequest->getUri()->getQuery(); parse_str($query, $params); $dgUrl = $this->deepgramUrl . '?' . http_build_query([ 'model' => $params['model'] ?? 'aura-asteria-en', 'encoding' => $params['encoding'] ?? 'linear16', 'sample_rate' => $params['sample_rate'] ?? '48000', 'container' => $params['container'] ?? 'none', ]); // Connect to Deepgram and set up bidirectional forwarding $connector = new Ratchet\Client\Connector(Loop::get()); $connector($dgUrl, [], ['Authorization' => 'Token ' . $this->apiKey]) ->then(function ($deepgramWs) use ($conn) { $this->clients[$conn] = $deepgramWs; // Forward Deepgram responses to client $deepgramWs->on('message', fn($msg) => $conn->send($msg->getPayload())); $deepgramWs->on('close', fn() => $conn->close()); }); } public function onMessage(ConnectionInterface $from, $msg): void { // Forward client messages to Deepgram if ($this->clients->contains($from) && $this->clients[$from]) { $this->clients[$from]->send($msg); } } public function onClose(ConnectionInterface $conn): void { if ($this->clients->contains($conn)) { $this->clients[$conn]?->close(); $this->clients->detach($conn); } } public function onError(ConnectionInterface $conn, Exception $e): void { $conn->close(); } } // Start server $server = IoServer::factory( new HttpServer(new WsServer(new LiveTextToSpeechProxy($apiKey))), 8081, '0.0.0.0' ); $server->run(); ``` -------------------------------- ### Check Server Health Source: https://context7.com/deepgram-starters/php-live-text-to-speech/llms.txt Verify the server status using the /health endpoint. ```bash # Check server health curl -s http://localhost:8081/health | python3 -m json.tool # Response: # { # "status": "ok" # } ``` -------------------------------- ### Web Audio API Playback Source: https://context7.com/deepgram-starters/php-live-text-to-speech/llms.txt Converts incoming Int16 PCM audio data to Float32 and schedules playback using the Web Audio API. ```javascript // Set up Web Audio API for playback const audioContext = new AudioContext({ sampleRate: 48000 }); const BUFFER_AHEAD_TIME = 0.1; // 100ms buffer before starting playback let audioQueue = []; let isPlaying = false; let nextStartTime = 0; // Convert Int16 PCM to Float32 for Web Audio API function int16ToFloat32(int16Array) { const float32Array = new Float32Array(int16Array.length); for (let i = 0; i < int16Array.length; i++) { float32Array[i] = int16Array[i] / 32768.0; } return float32Array; } // Handle incoming audio data ws.onmessage = (event) => { if (event.data instanceof ArrayBuffer) { const int16Data = new Int16Array(event.data); const float32Data = int16ToFloat32(int16Data); // Create audio buffer const audioBuffer = audioContext.createBuffer(1, float32Data.length, 48000); audioBuffer.getChannelData(0).set(float32Data); // Queue and schedule playback audioQueue.push(audioBuffer); schedulePlayback(); } }; function schedulePlayback() { if (audioQueue.length === 0) return; const currentTime = audioContext.currentTime; if (nextStartTime < currentTime) { nextStartTime = currentTime + BUFFER_AHEAD_TIME; } while (audioQueue.length > 0) { const buffer = audioQueue.shift(); const source = audioContext.createBufferSource(); source.buffer = buffer; source.connect(audioContext.destination); source.start(nextStartTime); nextStartTime += buffer.duration; } } ``` -------------------------------- ### Create and Validate JWT Session Tokens in PHP Source: https://context7.com/deepgram-starters/php-live-text-to-speech/llms.txt Handles JWT creation for session tokens and validation of tokens received via WebSocket subprotocol. Ensure the SESSION_SECRET environment variable is set. ```php time(), 'exp' => time() + $JWT_EXPIRY, ], $SESSION_SECRET, 'HS256'); } // Validate JWT from WebSocket subprotocol header function validateWsToken(?string $protocolHeader): ?string { global $SESSION_SECRET; if (!$protocolHeader) return null; foreach (explode(',', $protocolHeader) as $proto) { $proto = trim($proto); if (str_starts_with($proto, 'access_token.')) { $token = substr($proto, strlen('access_token.')); try { JWT::decode($token, new Key($SESSION_SECRET, 'HS256')); return $proto; // Return the full protocol string for response header } catch (\Exception $e) { return null; } } } return null; } ``` -------------------------------- ### Configure TTS WebSocket Parameters Source: https://context7.com/deepgram-starters/php-live-text-to-speech/llms.txt Define available query parameters for the Deepgram TTS WebSocket connection, including model, encoding, sample rate, and container format. Build the WebSocket URL with these parameters. ```javascript // Available query parameters for /api/live-text-to-speech const params = { // Voice model (default: 'aura-asteria-en') // Available: aura-asteria-en, aura-luna-en, aura-stella-en, aura-athena-en, // aura-hera-en, aura-orion-en, aura-arcas-en, aura-perseus-en, // aura-angus-en, aura-orpheus-en, aura-helios-en, aura-zeus-en model: 'aura-asteria-en', // Audio encoding (default: 'linear16') // Options: linear16, mp3, opus, mulaw, alaw encoding: 'linear16', // Sample rate in Hz (default: 48000) // Range: 8000-48000 sample_rate: '48000', // Container format (default: 'none') // Options: none, wav, ogg container: 'none' }; // Build WebSocket URL with parameters const wsUrl = new URL('ws://localhost:8081/api/live-text-to-speech'); Object.entries(params).forEach(([key, value]) => wsUrl.searchParams.set(key, value)); // Connect: ws://localhost:8081/api/live-text-to-speech?model=aura-asteria-en&encoding=linear16&sample_rate=48000&container=none ``` -------------------------------- ### TTS Query Parameters Source: https://context7.com/deepgram-starters/php-live-text-to-speech/llms.txt Configure the Deepgram TTS WebSocket connection with URL query parameters. These parameters allow customization of the voice model, audio encoding, sample rate, and container format. ```APIDOC ## TTS Query Parameters Configure the Deepgram TTS WebSocket connection with URL query parameters. ### Parameters #### Query Parameters - **model** (string) - Optional - Voice model to use. Defaults to 'aura-asteria-en'. Available options: aura-asteria-en, aura-luna-en, aura-stella-en, aura-athena-en, aura-hera-en, aura-orion-en, aura-arcas-en, aura-perseus-en, aura-angus-en, aura-orpheus-en, aura-helios-en, aura-zeus-en - **encoding** (string) - Optional - Audio encoding format. Defaults to 'linear16'. Options: linear16, mp3, opus, mulaw, alaw - **sample_rate** (string) - Optional - Sample rate in Hz. Defaults to '48000'. Range: 8000-48000 - **container** (string) - Optional - Container format for the audio stream. Defaults to 'none'. Options: none, wav, ogg ### Example Usage ```javascript const params = { model: 'aura-asteria-en', encoding: 'linear16', sample_rate: '48000', container: 'none' }; const wsUrl = new URL('ws://localhost:8081/api/live-text-to-speech'); Object.entries(params).forEach(([key, value]) => wsUrl.searchParams.set(key, value)); // Resulting URL: ws://localhost:8081/api/live-text-to-speech?model=aura-asteria-en&encoding=linear16&sample_rate=48000&container=none ``` ``` -------------------------------- ### Connect to WebSocket TTS Proxy Source: https://context7.com/deepgram-starters/php-live-text-to-speech/llms.txt Establishes a WebSocket connection with JWT authentication and configures TTS parameters via URL search parameters. ```javascript // JavaScript WebSocket client example async function connectTTS() { // 1. Get session token const sessionRes = await fetch('http://localhost:8081/api/session'); const { token } = await sessionRes.json(); // 2. Connect WebSocket with JWT auth and TTS parameters const wsUrl = new URL('ws://localhost:8081/api/live-text-to-speech'); wsUrl.searchParams.set('model', 'aura-asteria-en'); // Voice model wsUrl.searchParams.set('encoding', 'linear16'); // Audio encoding wsUrl.searchParams.set('sample_rate', '48000'); // Sample rate Hz wsUrl.searchParams.set('container', 'none'); // No container (raw PCM) const ws = new WebSocket(wsUrl.toString(), [`access_token.${token}`]); ws.binaryType = 'arraybuffer'; ws.onopen = () => { console.log('Connected to TTS proxy'); // Send text for synthesis ws.send(JSON.stringify({ type: 'Speak', text: 'Hello, welcome to Deepgram!' })); ws.send(JSON.stringify({ type: 'Speak', text: 'This is real-time text to speech.' })); // Flush to signal end of input and receive remaining audio ws.send(JSON.stringify({ type: 'Flush' })); }; ws.onmessage = (event) => { if (event.data instanceof ArrayBuffer) { // Binary audio data (Int16 PCM at 48kHz) const audioData = new Int16Array(event.data); // Process audio for playback... console.log(`Received ${audioData.length} audio samples`); } else { // JSON control messages from Deepgram const message = JSON.parse(event.data); console.log('Control message:', message); } }; ws.onerror = (error) => console.error('WebSocket error:', error); ws.onclose = (event) => console.log(`Connection closed: ${event.code} ${event.reason}`); return ws; } ``` -------------------------------- ### Issue JWT Session Token Source: https://context7.com/deepgram-starters/php-live-text-to-speech/llms.txt Retrieve a signed JWT token for WebSocket authentication via the /api/session endpoint. ```bash # Request a session token curl -s http://localhost:8081/api/session | python3 -m json.tool # Response: # { # "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE3MDk4MjE0MDAsImV4cCI6MTcwOTgyNTAwMH0.abc123..." # } # Store token for WebSocket authentication TOKEN=$(curl -s http://localhost:8081/api/session | jq -r '.token') echo "Session token: $TOKEN" ``` -------------------------------- ### WebSocket TTS Control Messages Source: https://context7.com/deepgram-starters/php-live-text-to-speech/llms.txt JSON message types used to control the synthesis process, including queuing text and managing the stream state. ```javascript // Message types for controlling TTS synthesis // Speak - Queue text for synthesis (can send multiple) ws.send(JSON.stringify({ type: 'Speak', text: 'Hello world, this text will be converted to speech.' })); // Flush - Signal end of text input, flush audio buffer ws.send(JSON.stringify({ type: 'Flush' })); // Clear - Cancel any pending audio generation ws.send(JSON.stringify({ type: 'Clear' })); // Close - Gracefully disconnect the WebSocket ws.send(JSON.stringify({ type: 'Close' })); ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.