OpenAI Chat Using OpenAI API AJAX PHP cURL

|

This is a PHP example that uses the OpenAI Chat API.

There are third party PHP libraries to access the OpenAI API via PHP. Instead of the third party PHP libraries, you also can use cURL in PHP. cURL is a library that lets you make HTTP requests in PHP

This is a demo example using HTML, CSS, Javascript, JQuery, AJAX, PHP and cURL.

OpenAI API Key

You need to obtain an OpenAI API key. You can get an account at OpenAI. It is free.

You need to use the OpenAI API key in the code. Embedding the OpenAI API key in the code is not a best practice. Some alternatives to embedding in code is putting it the system environmental file, you can create a hidden file or you can store it in a database. This example uses a name=value pair key in a hidden file. As a result the code has overhead for reading that file and parsing out the OpenAI API key.

		// Load the OpenAI API key
		$env_file = file_get_contents('.example-curl-01-env');
		$env_nvps = explode("\n", $env_file);
		$envs = array();
		foreach($env_nvps as $env_nvp){
			//error_log($env_nvp . PHP_EOL);
			$env = explode('=', $env_nvp);
			$envs[trim($env[0])] = trim($env[1]);
		}
		$api_key = $envs['OPENAI_API_KEY'];
		$data = array(
			"model" => $model, 
			"temperature" => 0.5,
			"max_tokens" => 500,
			'messages' => [
				[
					'role' => 'user',
					'content' => $_POST['prompt']
				],
			],
		);

You need to create that hidden file and replace PUT_YOUR_OPEN_AI_KEY_HERE with your OpenAI API key. Also be sure to include your file name on line 18.

OPENAI_API_KEY = PUT_YOUR_OPEN_AI_KEY_HERE

An alternative is have only your API key in the file and on line 18 load the file into the $api_key variable and eliminate the code lines 19- 26.

Validating the POST data.

This example does not have an elaborate data validation for the prompt text coming from the frontend. We can assume the OpenAI API does that. However if you plan to use it or store it, then you need to consider any other validation you require.

// Request validity status
$request_valid = false;
// Validate POST data
if (isset($_POST['prompt'])){
	$request_valid = true;
}
// Process request
if($request_valid){

Once the prompt is valid and the OpenAPI key is in hand, you then create the data needed to make the OpenAI API call.

Chat Completions Request

We are calling the chat completions request. This request “creates a completion for the chat message.”

The OpenAI Model

At this point in time I only had access to the OpenAI gpt-3.5-turbo model. The gpt-4 model was released but I was still on the wait list to use it via the API.

In the PHP code the model is on line 16. If you get access to gpt-4 model , you can substitute it or other models the API chat completion request we are using. Check model compatibility for a list of models.

		$model = 'gpt-3.5-turbo';

The request require various data values. One is the model id. The temperature for adjusting the sampling.

The max_tokens determine amount of usage. Lower you will get less and higher more. It impacts the utilization of token which are purchased. You can experiment on the tokenizer page. Set to 500 will generate a decent paragraph.

The messages array for the purpose of this demo is the user prompt. The user role is treating the request as you might expect in ChatGPT. The content is the prompt coming from the frontend.

		$data = array(
			"model" => $model, 
			"temperature" => 0.5,
			"max_tokens" => 500,
			'messages' => [
				[
					'role' => 'user',
					'content' => $_POST['prompt']
				],
			],
		);

cURL

URL is used to make the request. The details of using cURL are beyond the scope of this demo. However the code is a good template.

Line 40 provides the OpenAI API chat completions URL.

Line 43 encodes the data into JSON format and packages it as POST data.

Line 46 passes the OpenAI API key.

Line 48 executes the request and returns the results.

		// cURL processing
		$ch = curl_init();
		curl_setopt($ch, CURLOPT_URL, 'https://api.openai.com/v1/chat/completions');
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
		curl_setopt($ch, CURLOPT_POST, 1);
		curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
		$headers = array();
		$headers[] = 'Content-Type: application/json';
		$headers[] = 'Authorization: Bearer ' . $api_key;
		curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
		$response_raw = curl_exec($ch);

The AJAX response $rtn_val Variable

The remaining code packages the return data to send back to the client. The $rtn_val array contains the data the client side expects. The $rtn_val array success key is true if all went well and false otherwise. False is the default.

The $rtn_val array content key has the response from the OpenAI API if it succeeded.

The $rtn_val array error key is an array with information for perhaps messaging on the client side if the success key has a false value. The information in this example is scant and probably the best practice. The error key has a message key containing something identifying the reason for failure. As you will see it is not much.

Line 49 detects if there was some failure with the request. In that case the cURL error information is logged and the return message is set.

Lines 53-58 handles the success of the API request. For development learning only, the raw response is logged on line 53.

The raw response is encoded into JSON format on line 55 and logged for development learning only.

You can study those in your log file.

Line 57 is were the response content is extracted from the response. Line 58 sets the $rtn_val success key to true.

		if (curl_errno($ch)) {
			$rtn_val['error']['message'] = 'cannot-process-request';
			error_log 'Error:' . curl_error($ch);
		}else{
			error_log('$response_raw: ' . print_r($response_raw,true));
			// Convert response to JSON.
			$response = json_decode($response_raw);
			error_log('$response: ' . print_r($response_raw,true));
			$rtn_val['content'] = trim($response->choices[0]->message->content);
			$rtn_val['success'] = true;
		}

Finally the return data is packaged to return to the client in JSON format.

//Respond with JSON content
header('Content-Type: application/json');
echo json_encode( $rtn_val );

The try catch block.

A catch try block is also in place to catch any unexpected failures. It logs the error information and populates the error key message key.

PHP File

<?php
// Return values
$rtn_val = array();
$rtn_val['success'] = false;
// Request validity status
$request_valid = false;
// Validate POST data
if (isset($_POST['prompt'])){
	$request_valid = true;
}
// Process request
if($request_valid){
	try{
		// Create OpenAI API data
		//$model = 'text-davinci-003';
		$model = 'gpt-3.5-turbo';
		// Load the OpenAI API key
		$env_file = file_get_contents('.example-curl-01-env');
		$env_nvps = explode("\n", $env_file);
		$envs = array();
		foreach($env_nvps as $env_nvp){
			//error_log($env_nvp . PHP_EOL);
			$env = explode('=', $env_nvp);
			$envs[trim($env[0])] = trim($env[1]);
		}
		$api_key = $envs['OPENAI_API_KEY'];
		$data = array(
			"model" => $model, 
			"temperature" => 0.5,
			"max_tokens" => 500,
			'messages' => [
				[
					'role' => 'user',
					'content' => $_POST['prompt']
				],
			],
		);
		// cURL processing
		$ch = curl_init();
		curl_setopt($ch, CURLOPT_URL, 'https://api.openai.com/v1/chat/completions');
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
		curl_setopt($ch, CURLOPT_POST, 1);
		curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
		$headers = array();
		$headers[] = 'Content-Type: application/json';
		$headers[] = 'Authorization: Bearer ' . $api_key;
		curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
		$response_raw = curl_exec($ch);
		if (curl_errno($ch)) {
			$rtn_val['error']['message'] = 'cannot-process-request';
			error_log 'Error:' . curl_error($ch);
		}else{
			error_log('$response_raw: ' . print_r($response_raw,true));
			// Convert json response to PHP object.
			$response = json_decode($response_raw);
			error_log('$response: ' . print_r($response_raw,true));
			//$rtn_val['content'] = trim($response);
			$rtn_val['content'] = trim($response->choices[0]->message->content);
			$rtn_val['success'] = true;
		}
	}catch(\Tectalic\OpenAi\ClientException  $e){
		$rtn_val['error']['message'] = 'cannot-process-request';
		error_log('error: ' . $rtn_val['error']['message'] );
		error_log('$e: ' . print_r($e,true));
	}
}
//Respond with JSON content
header('Content-Type: application/json');
echo json_encode( $rtn_val );
?>
Expand

HTML File

<!doctype html>
<html lang="en">
<head>
	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width, initial-scale=1">
	<title>01 - OpenAI | Basic AJAX/PHP/cURL Test | Lon Hosford</title>
	<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.min.css">
	<link rel="stylesheet" href="example-curl-01.css">
	<title>Basic test of OpenAI with cURL and AJAX| Lon Hosford</title>
	<meta name="description" content="Basic test of OpenAI with HTML, CSS, Javascript, JQuery, AJAX, cURL and PHP ">
	<script src="https://code.jquery.com/jquery-3.6.3.min.js" integrity="sha256-pvPw+upLPUjgMXY0G+8O0xUf+/Im1MZjXxxgOcBQBXU=" crossorigin="anonymous"></script>
</head>
<body>
<div class="center-block text-align-center">
	<h1>OpenAI</h1>
	<h2>Basic test using cURL and AJAX</h2>
	<h5 class="center">Folder: openai/example-curl-01</h5>
	<p><a href="https://www.codesiri.com/2023/02/php-access-chatgpt-api-using-curl.html" target="_blank">PHP - Access ChatGPT API using cURL</a></p>
	<p><a href="https://platform.openai.com/docs/guides/completion/text-completion" target="_blank">OpenAI Text Completions Doc</a></p>
</div>
<div class="entry-form-container center-block text-align-center">
	<div><p class="text-align-left"><input id="prompt" type="text" placeholder="Enter a prompt" ><br>Ex: Describe the alkaline elements<br>What are the hardest rocks in the universe.</p></div>
	<div><p><button id="send">Send</button></p></div>
	<div><textarea id="results"></textarea></div>

</div>
<script src="example-curl-01.js"></script>
</body>
</html>

CSS File

.center-block{
	width: 100%;
	margin: auto;
}
.text-align-center{
	text-align: center;
}
.text-align-left{
	text-align: left;
}
#results{
	min-height: 100px;
	width: 100%;
}
.entry-form-container{
	width:500px;
}
#prompt{
	width: 100%;
}  

Javascript File

There are many console.log method calls in the code. This is for development learning. You can explore their output in the console of the web browser for study.

"use strict";
(function($){
	/*
	 * Handle #send button click event
	 * 
	 * Responds to #send button click event.
	 *  
	*/
	$('#send').on('click', function(e){
			e.preventDefault();
			console.log('CLICK!');
			sendPromptAjax();
	});
	/*
	 * Handle request to process a user prompt/
	 * 
	 * Sends prompt and update the UI with results.
	 *  
	 * @param int lessonId The lesson id
	*/
	function sendPromptAjax(){
		console.log('sendPromptAjax');
		$('#results').val('...processing...');
		let dataSend = {};
		dataSend['prompt'] = $('#prompt').val();
		console.log("sendPromptAjax| dataSend", dataSend);
		$.ajax(
			{
				type:"post",
				url:"example-curl-01.php",
				data:dataSend,
				dataType:'json',
			}
		)
		.done(
			function(data, status){
				console.log("sendPromptAjax | done");
				console.log("sendPromptAjax | data", data);
				console.log("sendPromptAjax | status", status);
				if (data.success){
					console.log("sendPromptAjax | Success true");
					$('#results').val(data.content);
				}else{
					$('#results').val('Request failed.');
				}
			}
		)
		.fail(
			function(data, status, error){
				console.log("sendPromptAjax | fail");
				console.log("sendPromptAjax | data", data);
				console.log("sendPromptAjax | error", error);
					$('#results').val('Something in cyberspace went horribly wrong!');
			}
		);
	}
})(jQuery);
Posted on March 30th, 2023 | Updated on April 22nd, 2023