# OpenAI PHP Client OpenAI PHP is a community-maintained PHP API client that provides a comprehensive interface for interacting with OpenAI's API. This library enables developers to access GPT models, DALL-E image generation, Whisper audio transcription, embeddings, fine-tuning, and other OpenAI services through an intuitive, type-safe PHP interface. Built with modern PHP 8.2+ features, it follows PSR standards and supports various HTTP clients through PSR-18 discovery. The client provides a factory pattern for flexible configuration, supports both synchronous and streaming responses, includes built-in error handling and rate limit management, and offers a comprehensive testing framework with fake implementations for all resources. It supports the latest OpenAI features including the Responses API, Conversations API, Vector Stores, Batches, and real-time communication endpoints. ## API Reference ### Client Initialization Initialize the OpenAI client with your API key to access all available resources. ```php withApiKey(getenv('OPENAI_API_KEY')) ->withOrganization('org-your-organization-id') ->withProject('Your Project Name') ->withBaseUri('api.openai.com/v1') ->withHttpClient(new \GuzzleHttp\Client(['timeout' => 120])) ->withHttpHeader('X-Custom-Header', 'value') ->withQueryParam('custom-param', 'value') ->make(); // Access different API resources $models = $client->models()->list(); $response = $client->chat()->create([ 'model' => 'gpt-4', 'messages' => [ ['role' => 'user', 'content' => 'Hello!'] ] ]); ``` ### Responses API - Create Model Response Create a model response with text or image inputs, supporting tools like web search and file search. ```php responses()->create([ 'model' => 'gpt-4o-mini', 'tools' => [ [ 'type' => 'web_search_preview' ] ], 'input' => 'What are the latest developments in quantum computing?', 'temperature' => 0.7, 'max_output_tokens' => 500, 'store' => true, 'metadata' => [ 'user_id' => 'user_12345', 'session_id' => 'session_abc' ] ]); echo "Response ID: {$response->id}\n"; echo "Status: {$response->status}\n"; echo "Model: {$response->model}\n"; echo "Text: {$response->outputText}\n"; foreach ($response->output as $output) { if ($output->type === 'message') { foreach ($output->content as $content) { if ($content->type === 'output_text') { echo "Content: {$content->text}\n"; } } } } echo "Tokens used: {$response->usage->totalTokens}\n"; ``` ### Responses API - Function Calling Create responses with custom function tools for extending model capabilities. ```php responses()->create([ 'model' => 'gpt-4o-mini', 'tools' => [ [ 'type' => 'function', 'name' => 'get_weather', 'description' => 'Get current weather for a location', 'parameters' => [ 'type' => 'object', 'properties' => [ 'location' => [ 'type' => 'string', 'description' => 'City and state, e.g. San Francisco, CA', ], 'unit' => [ 'type' => 'string', 'enum' => ['celsius', 'fahrenheit'], ], ], 'required' => ['location'], ], ] ], 'input' => 'What is the weather in Tokyo?', ]); foreach ($response->output as $item) { if ($item->type === 'function_call') { $functionName = $item->name; $arguments = json_decode($item->arguments, true); // Call your custom function $weather = getWeatherData($arguments['location'], $arguments['unit'] ?? 'celsius'); echo "Function called: {$functionName}\n"; echo "Arguments: " . json_encode($arguments) . "\n"; echo "Result: {$weather}\n"; } } function getWeatherData(string $location, string $unit): string { // Your implementation here return "22°C, Sunny"; } ``` ### Responses API - Streaming Stream model responses in real-time as they are generated. ```php responses()->createStreamed([ 'model' => 'gpt-4o-mini', 'input' => 'Explain the theory of relativity in simple terms', 'max_output_tokens' => 300, ]); foreach ($stream as $response) { switch ($response->event) { case 'response.created': echo "Response started: {$response->id}\n"; break; case 'response.output_item.content.delta': echo $response->delta; break; case 'response.output_item.done': echo "\nResponse completed\n"; break; case 'response.done': echo "Total tokens: {$response->usage->totalTokens}\n"; break; } } ``` ### Chat Completions - Standard Request Create chat completions with conversation history and system instructions. ```php chat()->create([ 'model' => 'gpt-4', 'messages' => [ ['role' => 'system', 'content' => 'You are a helpful coding assistant.'], ['role' => 'user', 'content' => 'How do I reverse a string in PHP?'], ], 'temperature' => 0.7, 'max_tokens' => 200, ]); echo "Chat ID: {$response->id}\n"; echo "Model: {$response->model}\n"; foreach ($response->choices as $choice) { echo "Role: {$choice->message->role}\n"; echo "Content: {$choice->message->content}\n"; echo "Finish Reason: {$choice->finishReason}\n"; } echo "Prompt Tokens: {$response->usage->promptTokens}\n"; echo "Completion Tokens: {$response->usage->completionTokens}\n"; echo "Total Tokens: {$response->usage->totalTokens}\n"; ``` ### Chat Completions - Tool Calling Use function tools to enable the model to call external functions. ```php chat()->create([ 'model' => 'gpt-4', 'messages' => [ ['role' => 'user', 'content' => 'What is the current stock price of AAPL?'], ], 'tools' => [ [ 'type' => 'function', 'function' => [ 'name' => 'get_stock_price', 'description' => 'Get the current stock price for a symbol', 'parameters' => [ 'type' => 'object', 'properties' => [ 'symbol' => [ 'type' => 'string', 'description' => 'Stock ticker symbol, e.g. AAPL', ], ], 'required' => ['symbol'], ], ], ] ], 'tool_choice' => 'auto', ]); foreach ($response->choices as $choice) { if ($choice->message->toolCalls) { foreach ($choice->message->toolCalls as $toolCall) { $functionName = $toolCall->function->name; $arguments = json_decode($toolCall->function->arguments, true); if ($functionName === 'get_stock_price') { $price = fetchStockPrice($arguments['symbol']); echo "Stock price for {$arguments['symbol']}: \${$price}\n"; } } } } function fetchStockPrice(string $symbol): float { // Your API call here return 175.50; } ``` ### Chat Completions - Streaming Stream chat responses token by token for real-time display. ```php chat()->createStreamed([ 'model' => 'gpt-4', 'messages' => [ ['role' => 'user', 'content' => 'Write a short story about a robot'], ], 'stream_options' => [ 'include_usage' => true, ], ]); foreach ($stream as $response) { if (isset($response->choices[0]->delta->content)) { echo $response->choices[0]->delta->content; flush(); } if ($response->usage !== null) { echo "\n\nTokens: {$response->usage->totalTokens}\n"; } } ``` ### Chat Completions - Vision Analyze images by providing image URLs or base64 encoded images. ```php chat()->create([ 'model' => 'gpt-4o', 'messages' => [ [ 'role' => 'user', 'content' => [ ['type' => 'text', 'text' => 'What objects are in this image?'], [ 'type' => 'image_url', 'image_url' => [ 'url' => 'https://example.com/image.jpg', 'detail' => 'high' ] ], ] ] ], 'max_tokens' => 300, ]); echo "Analysis: {$response->choices[0]->message->content}\n"; ``` ### Conversations API Create and manage persistent conversations for stateful interactions. ```php conversations()->create([ 'metadata' => ['user_id' => '12345', 'topic' => 'technical_support'], 'items' => [ [ 'type' => 'message', 'role' => 'user', 'content' => 'I need help with my account', ], ], ]); $conversationId = $conversation->id; echo "Conversation created: {$conversationId}\n"; // Add messages to conversation $client->conversations()->items()->create($conversationId, [ 'items' => [ [ 'role' => 'system', 'content' => 'You are a support agent. Be helpful and professional.', ], ], ]); // List all items in conversation $items = $client->conversations()->items()->list($conversationId, [ 'limit' => 50, ]); foreach ($items->data as $item) { echo "{$item->type} from {$item->role}: {$item->content}\n"; } // Update conversation metadata $client->conversations()->update($conversationId, [ 'metadata' => ['status' => 'resolved'], ]); // Delete conversation when done $client->conversations()->delete($conversationId); ``` ### Embeddings - Create Vectors Generate vector embeddings for text to enable semantic search and similarity. ```php embeddings()->create([ 'model' => 'text-embedding-3-small', 'input' => [ 'The quick brown fox jumps over the lazy dog', 'Machine learning is a subset of artificial intelligence', 'PHP is a popular server-side scripting language', ], ]); echo "Total embeddings: " . count($response->embeddings) . "\n"; foreach ($response->embeddings as $embedding) { $vectorLength = count($embedding->embedding); $firstValues = array_slice($embedding->embedding, 0, 5); echo "Embedding {$embedding->index}: {$vectorLength} dimensions\n"; echo "First values: [" . implode(', ', $firstValues) . "...]\n"; } echo "Prompt tokens used: {$response->usage->promptTokens}\n"; // Calculate cosine similarity between two embeddings function cosineSimilarity(array $vec1, array $vec2): float { $dot = array_sum(array_map(fn($a, $b) => $a * $b, $vec1, $vec2)); $mag1 = sqrt(array_sum(array_map(fn($x) => $x * $x, $vec1))); $mag2 = sqrt(array_sum(array_map(fn($x) => $x * $x, $vec2))); return $dot / ($mag1 * $mag2); } ``` ### Audio - Text to Speech Generate spoken audio from text input with various voice options. ```php audio()->speech([ 'model' => 'tts-1-hd', 'input' => 'Welcome to our service. How can I help you today?', 'voice' => 'alloy', 'response_format' => 'mp3', 'speed' => 1.0, ]); file_put_contents('output.mp3', $audioContent); echo "Audio saved to output.mp3\n"; // Stream audio for large texts $stream = $client->audio()->speechStreamed([ 'model' => 'tts-1', 'input' => 'This is a longer text that will be streamed...', 'voice' => 'nova', ]); $handle = fopen('streamed_output.mp3', 'wb'); foreach ($stream as $chunk) { fwrite($handle, $chunk); } fclose($handle); echo "Streamed audio saved\n"; ``` ### Audio - Speech to Text Transcribe audio files to text with detailed segment and word-level timestamps. ```php audio()->transcribe([ 'model' => 'whisper-1', 'file' => fopen('meeting_recording.mp3', 'r'), 'response_format' => 'verbose_json', 'timestamp_granularities' => ['segment', 'word'], 'language' => 'en', ]); echo "Task: {$response->task}\n"; echo "Language: {$response->language}\n"; echo "Duration: {$response->duration}s\n"; echo "Full text: {$response->text}\n\n"; // Process segments foreach ($response->segments as $segment) { $start = gmdate('H:i:s', (int)$segment->start); $end = gmdate('H:i:s', (int)$segment->end); echo "[{$start} -> {$end}] {$segment->text}\n"; } // Word-level timestamps foreach ($response->words as $word) { echo "{$word->word} ({$word->start}s - {$word->end}s)\n"; } ``` ### Audio - Translation Translate audio from any language to English. ```php audio()->translate([ 'model' => 'whisper-1', 'file' => fopen('spanish_audio.mp3', 'r'), 'response_format' => 'json', ]); echo "Translated text: {$response->text}\n"; ``` ### Images - Generate Create images from text descriptions using DALL-E models. ```php images()->create([ 'model' => 'dall-e-3', 'prompt' => 'A futuristic city at sunset with flying cars and neon lights, cyberpunk style', 'size' => '1024x1024', 'quality' => 'hd', 'n' => 1, 'response_format' => 'url', ]); foreach ($response->data as $image) { echo "Image URL: {$image->url}\n"; echo "Revised prompt: {$image->revisedPrompt}\n"; // Download the image $imageData = file_get_contents($image->url); file_put_contents('generated_image.png', $imageData); } echo "Created at: {$response->created}\n"; ``` ### Images - Edit Modify existing images with text prompts using a mask. ```php images()->edit([ 'image' => fopen('original.png', 'r'), 'mask' => fopen('mask.png', 'r'), 'prompt' => 'Add a red car in the driveway', 'model' => 'dall-e-2', 'size' => '1024x1024', 'n' => 1, ]); foreach ($response->data as $image) { $imageData = file_get_contents($image->url); file_put_contents('edited_image.png', $imageData); echo "Edited image saved\n"; } ``` ### Images - Create Variation Generate variations of an existing image. ```php images()->variation([ 'image' => fopen('input_image.png', 'r'), 'n' => 3, 'size' => '512x512', 'response_format' => 'url', ]); foreach ($response->data as $index => $image) { echo "Variation {$index}: {$image->url}\n"; file_put_contents("variation_{$index}.png", file_get_contents($image->url)); } ``` ### Models - List and Retrieve Access information about available models and their capabilities. ```php models()->list(); echo "Available models:\n"; foreach ($response->data as $model) { echo "- {$model->id} (owned by {$model->ownedBy})\n"; } // Retrieve specific model details $model = $client->models()->retrieve('gpt-4'); echo "\nModel: {$model->id}\n"; echo "Created: " . date('Y-m-d H:i:s', $model->created) . "\n"; echo "Owned by: {$model->ownedBy}\n"; ``` ### Fine-tuning - Create and Manage Jobs Create custom models fine-tuned on your specific data. ```php files()->upload([ 'file' => fopen('training_data.jsonl', 'r'), 'purpose' => 'fine-tune', ]); // Create fine-tuning job $job = $client->fineTuning()->createJob([ 'training_file' => $file->id, 'model' => 'gpt-3.5-turbo', 'hyperparameters' => [ 'n_epochs' => 3, ], 'suffix' => 'custom-model', ]); echo "Fine-tuning job created: {$job->id}\n"; echo "Status: {$job->status}\n"; // Monitor job progress while (true) { $status = $client->fineTuning()->retrieveJob($job->id); echo "Current status: {$status->status}\n"; if (in_array($status->status, ['succeeded', 'failed', 'cancelled'])) { break; } sleep(10); } if ($status->status === 'succeeded') { echo "Fine-tuned model: {$status->fineTunedModel}\n"; echo "Trained tokens: {$status->trainedTokens}\n"; } // List job events $events = $client->fineTuning()->listJobEvents($job->id); foreach ($events->data as $event) { echo "[" . date('Y-m-d H:i:s', $event->createdAt) . "] {$event->message}\n"; } ``` ### Files - Upload and Manage Upload and manage files for use with various OpenAI features. ```php files()->upload([ 'file' => fopen('dataset.jsonl', 'r'), 'purpose' => 'fine-tune', ]); echo "File uploaded: {$file->id}\n"; echo "Filename: {$file->filename}\n"; echo "Size: {$file->bytes} bytes\n"; echo "Status: {$file->status}\n"; // List all files $files = $client->files()->list(); foreach ($files->data as $file) { echo "{$file->id}: {$file->filename} ({$file->purpose})\n"; } // Retrieve file info $fileInfo = $client->files()->retrieve($file->id); echo "Created at: " . date('Y-m-d H:i:s', $fileInfo->createdAt) . "\n"; // Download file content $content = $client->files()->download($file->id); file_put_contents('downloaded_file.jsonl', $content); // Delete file $result = $client->files()->delete($file->id); echo "Deleted: " . ($result->deleted ? 'Yes' : 'No') . "\n"; ``` ### Vector Stores - Search and Manage Create vector stores for semantic search over your documents. ```php vectorStores()->create([ 'name' => 'Product Documentation', 'file_ids' => [], ]); echo "Vector store created: {$vectorStore->id}\n"; // Upload and add files $file = $client->files()->upload([ 'file' => fopen('documentation.pdf', 'r'), 'purpose' => 'assistants', ]); $vectorFile = $client->vectorStores()->files()->create($vectorStore->id, [ 'file_id' => $file->id, ]); echo "File added to vector store\n"; // Wait for processing while (true) { $status = $client->vectorStores()->files()->retrieve($vectorStore->id, $file->id); if ($status->status === 'completed') { break; } sleep(5); } // Search the vector store $searchResults = $client->vectorStores()->search($vectorStore->id, [ 'query' => 'How do I reset my password?', 'max_num_results' => 5, 'rewrite_query' => false, ]); foreach ($searchResults->data as $result) { echo "File: {$result->filename}\n"; echo "Score: {$result->score}\n"; foreach ($result->content as $content) { echo "Content: {$content->text}\n"; } echo "\n"; } // Clean up $client->vectorStores()->delete($vectorStore->id); ``` ### Batches - Asynchronous Processing Process large numbers of requests asynchronously with cost savings. ```php 'request-1', 'method' => 'POST', 'url' => '/v1/chat/completions', 'body' => [ 'model' => 'gpt-4', 'messages' => [ ['role' => 'user', 'content' => 'What is PHP?'] ], ], ], [ 'custom_id' => 'request-2', 'method' => 'POST', 'url' => '/v1/chat/completions', 'body' => [ 'model' => 'gpt-4', 'messages' => [ ['role' => 'user', 'content' => 'Explain REST APIs'] ], ], ], ]; file_put_contents('batch_input.jsonl', implode("\n", array_map('json_encode', $batchRequests))); // Upload batch file $file = $client->files()->upload([ 'file' => fopen('batch_input.jsonl', 'r'), 'purpose' => 'batch', ]); // Create batch $batch = $client->batches()->create([ 'input_file_id' => $file->id, 'endpoint' => '/v1/chat/completions', 'completion_window' => '24h', 'metadata' => ['description' => 'Daily batch job'], ]); echo "Batch created: {$batch->id}\n"; echo "Status: {$batch->status}\n"; // Poll for completion while (true) { $status = $client->batches()->retrieve($batch->id); echo "Status: {$status->status}\n"; if ($status->requestCounts) { echo "Completed: {$status->requestCounts->completed}/{$status->requestCounts->total}\n"; } if (in_array($status->status, ['completed', 'failed', 'expired'])) { break; } sleep(60); } // Download results if ($status->outputFileId) { $results = $client->files()->download($status->outputFileId); file_put_contents('batch_output.jsonl', $results); echo "Results downloaded\n"; } ``` ### Containers - Code Interpreter Create containers for executing code with the Code Interpreter tool. ```php containers()->create([ 'name' => 'Data Analysis Container', 'expires_after' => [ 'anchor' => 'last_active_at', 'minutes' => 120, ], ]); echo "Container created: {$container->id}\n"; echo "Status: {$container->status}\n"; // Upload files to container $file = $client->containers()->files()->create($container->id, [ 'file' => fopen('data.csv', 'r'), ]); echo "File uploaded to container: {$file->path}\n"; // List container files $files = $client->containers()->files()->list($container->id); foreach ($files->data as $file) { echo "- {$file->path} ({$file->bytes} bytes)\n"; } // Retrieve file content $content = $client->containers()->files()->content($container->id, $file->id); echo "File content:\n{$content}\n"; // Delete container when done $client->containers()->delete($container->id); ``` ### Moderations - Content Safety Check content for policy violations and safety concerns. ```php moderations()->create([ 'model' => 'text-moderation-latest', 'input' => [ 'Hello, this is a normal message.', 'This might contain inappropriate content...', ], ]); echo "Model: {$response->model}\n"; foreach ($response->results as $index => $result) { echo "\nInput {$index}:\n"; echo "Flagged: " . ($result->flagged ? 'Yes' : 'No') . "\n"; if ($result->flagged) { foreach ($result->categories as $category) { if ($category->violated) { echo "- {$category->category->value}: {$category->score}\n"; } } } } ``` ### Error Handling and Rate Limits Handle API errors and monitor rate limits across all endpoints. ```php chat()->create([ 'model' => 'gpt-4', 'messages' => [ ['role' => 'user', 'content' => 'Hello!'] ], ]); // Access rate limit information $meta = $response->meta(); echo "Request ID: {$meta->requestId}\n"; echo "Model: {$meta->openai->model}\n"; echo "Processing time: {$meta->openai->processingMs}ms\n"; // Rate limits echo "Request limit: {$meta->requestLimit->remaining}/{$meta->requestLimit->limit}\n"; echo "Request reset: {$meta->requestLimit->reset}\n"; echo "Token limit: {$meta->tokenLimit->remaining}/{$meta->tokenLimit->limit}\n"; echo "Token reset: {$meta->tokenLimit->reset}\n"; } catch (ErrorException $e) { // API returned an error echo "API Error: {$e->getMessage()}\n"; echo "Type: {$e->getErrorType()}\n"; echo "Code: {$e->getErrorCode()}\n"; } catch (TransporterException $e) { // Network or transport error echo "Transport Error: {$e->getMessage()}\n"; } catch (\Exception $e) { // Other errors echo "Unexpected Error: {$e->getMessage()}\n"; } ``` ### Testing with Fakes Test your OpenAI integration without making real API calls. ```php [ [ 'message' => [ 'role' => 'assistant', 'content' => 'This is a fake response for testing', ], ], ], ]), ]); // Use the client as normal $response = $client->chat()->create([ 'model' => 'gpt-4', 'messages' => [ ['role' => 'user', 'content' => 'Test message'], ], ]); echo $response->choices[0]->message->content; // Assert requests were sent correctly $client->assertSent(\OpenAI\Resources\Chat::class, function ($method, $parameters) { return $method === 'create' && $parameters['model'] === 'gpt-4' && $parameters['messages'][0]['content'] === 'Test message'; }); // Assert request count $client->assertSent(\OpenAI\Resources\Chat::class, 1); // Assert specific resource was not called $client->assertNotSent(\OpenAI\Resources\Completions::class); ``` ## Integration and Use Cases OpenAI PHP Client serves as a versatile foundation for building AI-powered PHP applications across multiple domains. Common use cases include building conversational chatbots and customer support systems using the Chat and Conversations APIs, implementing semantic search and recommendation systems with Embeddings and Vector Stores, creating content generation and summarization tools with GPT models, developing voice interfaces with text-to-speech and speech-to-text capabilities, generating marketing materials and social media content with DALL-E image generation, and building custom AI solutions through fine-tuning. The library's streaming capabilities enable real-time interactive experiences, while batch processing support allows cost-effective handling of high-volume workloads. The client integrates seamlessly with modern PHP frameworks and follows PSR standards for HTTP clients, making it compatible with Guzzle, Symfony HTTP Client, and other PSR-18 implementations. The factory pattern enables flexible configuration for different environments, including Azure OpenAI Service support through custom base URIs and headers. Built-in testing utilities with fake implementations allow developers to write comprehensive tests without API costs or rate limits. The library handles complex scenarios like function calling for custom tool integration, webhook signature verification for event-driven architectures, streaming responses for improved user experience, and robust error handling with detailed rate limit information. Whether building simple chatbots or complex AI-powered applications, OpenAI PHP Client provides the reliability, type safety, and developer experience needed for production systems.