<?php
$apiKey = "your-openai-api-key-here"; # set your openai key here
// version: 1.0
// filename: example.phpopenaichat.php
// author: https://www.phpclasses.org/browse/author/144301.html
// description: An application to hold conversations using the OpenAI API to access the GPT-3.5-Turbo model and the GPT-4 model.
// license: BSD License
// TODO: DONE. Conversation loading/saving
// TODO: DONE. Edit previous message sections by clicking their div in the window to change their content
// TODO: When contracting messages array to fit into maxtokens, start throwing away everything after first agent and first prompt.
// TODO: A oneshot section for a single message that is not part of the conversation.
// TODO: DONE. save/load agent
/*
Description:
An application to hold conversations using the OpenAI API to access the GPT-3.5-Turbo model and the GPT-4 model.
Very versatile and lets you edit the conversation's past to change the future responses.
Let's you save/load/delete conversations and agents using JSON flatfiles.
Programmed using PHP 8. Uses jQuery CDN for jQuery. PHP Curl required to connect to API with class.phpopenaichat.php.
I found ChatGPT to be lacking, so I made my own.
Messages in conversation only show an excerpt. Click on them to see the full message.
*/
/*
Features:
- uses class class.phpopenaichat.php to drive the application's API request.
- Persistent conversation using $_SESSION
- Persistent controls that dynamically update on the server side whenever they are changed client side
- Using jQuery to dynamically update the page without reloading it
- Ability to save/load/delete conversations in a JSON file in the _saved directory (create in this program's root, and set as read/writeable
- Ability to edit previous conversation messages by clicking on them in the window (Both agent and user messages can be edited)
- Ability to save/load/delete agent into a JSON file in the _saved_agents directory (create in this program's root, and set as read/writeable
- Minimal CSS styling for better code clarity
- Ability to change the model, temperature, frequency penalty, presence penalty, and max tokens, previous conversation, and agent between prompts
- frequency penalty, presence penalty let the AI know to not repeat itself or to not repeat the user's input
- temperature is how random the AI's response is. 0.0 is the most predictable, 1.0+ is the most random
- agents help the model align to a specific style of conversation. (ie. a doctor, a lawyer, a child, a teenager, a parent, etc.)
- multiuser - Can run multiple instances at same time, but just use different browsers or a private window so that each instance has its own session.
- GPT 4 is in beta at the moment, so you have to request access.
- API access costs money, so be aware of that. (gpt 3.5 turbo is dirt cheap at the moment)
- This is not secured for production use. It is just a proof of concept, and made for closed/private access from trusted individuals.
- Using a command processor on the return from the server let's the server dynamically redefine the controls on the client side.
- server has a copy of the clients data, so client's side is more of an indicator than a director.
- API can take a few seconds to return a response, so be patient when it seems nothing is working after sending a prompt.
devnotes: june 2023
- added to example:
- added support for gpt-3.5-turbo-16k (16k token model of gpt-3.5-turbo)
- added support for gpt-4-32k (32k token model of gpt-4)
*/
// start our session for persistent parts of the application
ob_start(); session_start();
// destroy session
// session_destroy(); exit;
// setting some defaults for the application
if(!isset($_SESSION['messages']))
$_SESSION['messages'] = []; // current conversation
if(!isset($_SESSION['agent']))
$_SESSION['agent'] = "You are a friendly and helpful assistant.";
if(!isset($_SESSION['model']))
$_SESSION['model'] = "gpt-3.5-turbo"; // default model
if(!isset($_SESSION['temperature']))
$_SESSION['temperature'] = 1.0; // default temperature
if(!isset($_SESSION['freq_penalty']))
$_SESSION['freq_penalty'] = 0.0; // default frequency penalty
if(!isset($_SESSION['pres_penalty']))
$_SESSION['pres_penalty'] = 0.0; // default presence penalty
if(!isset($_SESSION['max_tokens']))
$_SESSION['max_tokens'] = 4090; // default max tokens
# ---
require_once('class.phpopenaichat.php');
// create new instance of PHPOpenAIChat
$openAIChat = new PHPOpenAIChat($apiKey);
// unused?... for now
function send_and_append($prompt, $messages)
{
global $openAIChat;
$response = $openAIChat->sendMessage($messages);
$text = $openAIChat->get_response_text($response);
$messages = $openAIChat->append_response_to_messages($messages, $text);
return $messages;
} // end send_and_append()
function html_messages($messages)
{
if(empty($messages))
return '';
$html = '
<style>
.messages {
padding-bottom:200px;
}
.message_content textarea {
width: 98%;
/* height: 100%; */
height:auto;
border: none;
background-color: transparent;
}
</style>
';
$row_count = 0;
$even_odd = "odd";
foreach($messages as $message)
{
$the_content = htmlentities($message['content']);
$html .= '<div class="message '.$even_odd.'" row_count="'.$row_count.'" >';
$html .= '<div class="message_role">'.$message['role'].'</div>';
$html .= '<div class="message_content"><textarea class="autoExpand" name="message_content_textarea" row_count="'.
$row_count.'" onchange="btn_update_message_content(this);">'.
$the_content.'</textarea></div>';
$html .= '</div>';
$row_count++;
$even_odd = ($even_odd == "even") ? "odd" : "even";
}
return $html;
} // end html_messages()
function change_message_content($messages, $index, $content)
{
// will let us click and edit a message div and have ajax send back to server to change conversation history
$messages[$index]['content'] = $content;
return $messages;
} // end change_message_content()
function get_conversation_titles()
{
$titles = [];
$files = glob('_saved/*.json');
foreach($files as $file)
{
$json = file_get_contents($file);
$json = json_decode($json, true);
// substr out the _saved/ part of the filename
$just_file = substr($file, strlen('_saved/') );
$titles[] = [
'title' => $json['title'],
'file' => $just_file
];
}
return $titles;
} // end get_conversation_titles()
function html_conversation_combobox()
{
// return the html for a dropdown combobox of all the saved conversations
$titles = get_conversation_titles();
$html = '<select id="conversation_combobox" name="conversation_combobox" >';
foreach($titles as $title)
{
$html .= '<option value="'.$title['file'].'">'.$title['title'].'</option>';
}
$html .= '</select>';
return $html;
}
function get_agents_titles()
{
$titles = [];
$files = glob('_saved_agents/*.json');
foreach($files as $file)
{
$json = file_get_contents($file);
$json = json_decode($json, true);
// substr out the _agents/ part of the filename
$just_file = substr($file, strlen('_saved_agents/') );
$titles[] = [
'title' => $json['title'],
'file' => $just_file
];
}
return $titles;
} // end get_agents_titles()
function html_agents_combobox()
{
// return the html for a dropdown combobox of all the saved agents
$titles = get_agents_titles();
$html = '<select id="agents_combobox" name="agents_combobox" >';
foreach($titles as $title)
{
$html .= '<option value="'.$title['file'].'">'.$title['title'].'</option>';
}
$html .= '</select>';
return $html;
} // end html_agents_combobox()
# ---
# gets ajax request and then returns json data and quits.
if(!empty($_GET['ajax']))
{
switch($_GET['ajax'])
{
case 'delete_conversation':
$file = $_POST['flds']['file'];
$file = trim($file);
if(empty($file)) {
$return_arr[] = array(
"command" => 'alert',
"process" => "delete_conversation",
"msg" => "file empty"
);
break; // error: no file specified
}
$file = '_saved/'.$file;
// if file doesn't exist error out
if(!file_exists($file)) {
$return_arr[] = array(
"command" => 'alert',
"process" => "delete_conversation",
"msg" => "file does not exist"
);
break; // error: file does not exist
}
unlink($file);
$return_arr[] = array(
"command" => 'alert',
"process" => "delete_conversation",
"msg" => "file deleted"
);
$return_arr[] = array(
"command" => 'html',
"selector" => '#conversation_combobox',
"msg" => html_conversation_combobox()
);
break;
case 'load_conversation':
$file = $_POST['flds']['file'];
$file = trim($file);
if(empty($file)) {
$return_arr[] = array(
"command" => 'alert',
"process" => "load_conversation",
"msg" => "file empty"
);
break; // error: no file specified
}
$file = '_saved/'.$file;
// if file doesn't exist error out
if(!file_exists($file)) {
$return_arr[] = array(
"command" => 'alert',
"process" => "load_conversation",
"msg" => "file does not exist"
);
break; // error: file does not exist
}
$json = file_get_contents($file);
$json = json_decode($json, true);
$messages = $json['messages'];
$_SESSION['messages'] = $messages;
$messages_html = html_messages($messages);
$return_arr[] = array(
"command" => 'html',
"process" => "load_conversation",
"selector" => '.output',
"msg" => $messages_html
);
// update textareas
$return_arr[] = array(
"command" => 'resize_textareas',
"process" => "load_conversation"
);
break;
case 'save_conversation':
$conversation_title = $_POST['flds']['title'];
$messages = $_SESSION['messages'];
// now create a folder named '_saved' and save the conversation as a json file in that folder
// file will be a timestamp_hash.json
// json will be format:
// "title": "conversation title",
// "messages": {$_SESSION['messages']}
// create folder if it doesn't exist
if(!file_exists('_saved'))
@mkdir('_saved');
// if dir doesn't exist... abort with alert error
if(!file_exists('_saved'))
{
$return_arr[] = array(
"command" => 'alert',
"process" => "save_conversation",
"msg" => "could not create _saved folder"
);
break; // error: could not create _saved folder
}
// create a unique filename
$filename = time().'_'.md5(time()).'.json';
$filepath = '_saved/'.$filename;
// save the file...
$json_data = array(
"title" => $conversation_title,
"messages" => $messages
);
$json_data = json_encode($json_data);
// store it to file
$result = file_put_contents($filepath, $json_data);
// create json data
$json_data = array(
"title" => $conversation_title,
"messages" => $messages
);
$return_arr[] = array(
"command" => 'alert',
"process" => "save_conversation",
"msg" => "saved conversation"
);
$return_arr[] = array(
"command" => 'val',
'selector' => 'input[name="save-message_title"]',
'msg' => ''
);
$return_arr[] = array(
"command" => 'html',
"selector" => '#conversation_combobox',
"msg" => html_conversation_combobox()
);
break; // case 'save_conversation'
case 'change_message_content':
$index = $_POST['flds']['row_count'];
$content = $_POST['flds']['message_content'];
$messages = $_SESSION['messages'];
$messages = change_message_content($messages, $index, $content);
$_SESSION['messages'] = $messages;
$return_arr[] = array(
"command" => 'alert',
"process" => "change_message_content",
"msg" => "changed message content",
"index" => $index,
"content" => $content
);
break; // case 'change_message_content'
case 'update_conversation':
$messages = $_SESSION['messages'];
$html_messages = html_messages($messages);
$return_arr[] = array(
"command" => 'html',
'selector' => '.output',
'msg' => $html_messages
);
break; // case 'update_conversation'
case 'delete_agent':
$file = $_POST['flds']['file'];
$file = trim($file);
if(empty($file)) {
$return_arr[] = array(
"command" => 'alert',
"process" => "delete_agent",
"msg" => "file empty"
);
break; // error: no file specified
}
$file = '_saved_agents/'.$file;
// if file doesn't exist error out
if(!file_exists($file)) {
$return_arr[] = array(
"command" => 'alert',
"process" => "delete_agent",
"msg" => "file does not exist"
);
break; // error: file does not exist
}
unlink($file);
$return_arr[] = array(
"command" => 'alert',
"process" => "delete_agent",
"msg" => "file deleted"
);
$return_arr[] = array(
"command" => 'html',
"selector" => '#agents_combobox',
"msg" => html_agents_combobox()
);
break;
case 'save_agent':
$agent_name = $_POST['flds']['title'];
$agent = $_SESSION['agent'];
// create folder if it doesn't exist
if(!file_exists('_saved_agents'))
@mkdir('_saved_agents');
// if dir doesn't exist... abort with alert error
if(!file_exists('_saved_agents'))
{
$return_arr[] = array(
"command" => 'alert',
"process" => "save_agent",
"msg" => "could not create _saved_agents folder"
);
break; // error: could not create _saved_agents folder
}
// create a unique filename
$filename = time().'_'.md5(time()).'.json';
$filepath = '_saved_agents/'.$filename;
// save the file...
$json_data = array(
"title" => $agent_name,
"agent" => $agent
);
$json_data = json_encode($json_data);
// store it to file
$result = file_put_contents($filepath, $json_data);
$return_arr[] = array(
"command" => 'alert',
"process" => "save_agent",
"msg" => "saved agent"
);
$return_arr[] = array(
"command" => 'val',
'selector' => 'input[name="save-agent_title"]',
'msg' => ''
);
$return_arr[] = array(
"command" => 'html',
"selector" => '#agents_combobox',
"msg" => html_agents_combobox()
);
break; // case 'save_assistant'
case 'load_agent':
$file = $_POST['flds']['file'];
$file = trim($file);
if(empty($file)) {
$return_arr[] = array(
"command" => 'alert',
"process" => "load_agent",
"msg" => "file empty"
);
break; // error: no file specified
}
$file = '_saved_agents/'.$file;
// if file doesn't exist error out
if(!file_exists($file)) {
$return_arr[] = array(
"command" => 'alert',
"process" => "load_agent",
"msg" => "file does not exist"
);
break; // error: file does not exist
}
$json = file_get_contents($file);
$json = json_decode($json, true);
$agent = $json['agent'];
$_SESSION['agent'] = $agent;
$return_arr[] = array(
"command" => 'val',
"process" => "load_agent",
"selector" => '#text_agent',
"msg" => $agent
);
break; // case 'load_agent'
case 'one-shot':
// function one_shot($api_key, $prompt, $agent='You are a helpful assistant.', $temperature=1.0, $max_tokens=4000, $model="gpt-3.5-turbo")
// returns text
/*
"prompt": $('textarea[name="prompt"]').val(),
"agent": $('textarea[name="agent"]').val(),
"temperature": $('input[name="temperature"]').val(),
"max_tokens": $('input[name="max_tokens"]').val(),
*/
global $apiKey;
$prompt = $_POST['flds']['prompt'];
$agent = $_POST['flds']['agent'];
$temperature = $_POST['flds']['temperature'];
$max_tokens = 4000;
$model = $_POST['flds']['model'];
$api_key = $apiKey;
// trim and clean $prompt
$prompt = trim($prompt);
// if prompt empty return error
$text = one_shot($api_key, $prompt, $agent, $temperature, $max_tokens, $model);
$return_arr[] = array(
"command" => 'val',
"process" => "one-shot",
"selector" => 'textarea[name="response"]',
"msg" => $text
);
$return_arr[] = array(
'command' => 'enable_input',
'selector' => '.one_shot .the-button'
);
break; // case 'one-shot'
// ---------------------------------------------------------------------
case 'prompt':
$prompt = $_POST['flds']['prompt'];
// trim and clean $prompt
$prompt = trim($prompt);
// if prompt empty return error
if(empty($prompt))
{
$return_arr[] = array(
"command" => 'alert',
"process" => "prompt",
"msg" => "prompt is empty"
);
} else {
$messages = $_SESSION['messages'];
// first set agent
$messages = $openAIChat->set_agent($messages, $_SESSION['agent']);
$openAIChat->model = $_SESSION['model'];
$openAIChat->temperature = (float) round($_SESSION['temperature'],1);
$openAIChat->freq_penalty = (float) round($_SESSION['freq_penalty'],1);
$openAIChat->pres_penalty = (float) round($_SESSION['pres_penalty'],1);
$openAIChat->set_max_tokens( 4090 );
// print_r($prompt);
// add prompt to messages conversation
$messages = $openAIChat->add_prompt_to_messages($messages, $prompt);
// print("\r\n\r\n");
// print_r($messages);
$response = $openAIChat->sendMessage($messages);
$text = $openAIChat->get_response_text($response);
// print_r($response);
// print("\r\n\r\n-----------\r\n\r\n");
// print($text);
// if text empty return error
if(empty($text))
{
$return_arr[] = array(
"command" => 'alert',
"process" => "prompt",
"msg" => "api error:returned nothing",
"model" => $_SESSION['model'],
"response" => $response
);
break;
}
// append response to messages conversation
$messages = $openAIChat->append_response_to_messages($messages, $text);
// save messages to session
$_SESSION['messages'] = $messages;
$return_arr[] = array(
"command" => 'success',
"process" => "prompt",
"prompt" => $prompt,
"agent" => $_SESSION['agent'],
"model" => $_SESSION['model'],
"temperature" => $_SESSION['temperature'],
"freq_penalty" => $_SESSION['freq_penalty'],
"pres_penalty" => $_SESSION['pres_penalty'],
"max_tokens" => $_SESSION['max_tokens'],
"text" => $text,
"response" => $response
);
$return_arr[] = array(
"command" => 'update_conversation'
);
$return_arr[] = array(
"command" => 'val',
'selector' => 'textarea[name="text_prompt"]',
'msg' => ''
);
$return_arr[] = array(
'command' => 'html',
'selector' => '.output',
'msg' => html_messages($messages)
);
$return_arr[] = array(
'command' => 'enable_input',
'selector' => '#send-button'
);
$return_arr[] = array(
'command' => 'resize_textareas'
);
}
break; // case 'prompt'
// ---------------------------------------------------------------------
case 'change_agent':
$agent = $_POST['flds']['agent'];
$_SESSION['agent'] = $agent;
$return_arr[] = array(
"command" => 'success',
"process" => "change_agent"
);
$return_arr[] = array(
"command" => 'response_text',
"agent" => $agent
);
break; // case 'change_agent'
case 'change_model':
$model = $_POST['flds']['model'];
$_SESSION['model'] = $model;
$return_arr[] = array(
"command" => 'success',
"process" => "change_model",
"model" => $model
);
break; // case 'change_model'
case 'change_temperature':
$temperature = $_POST['flds']['temperature'];
$_SESSION['temperature'] = $temperature;
$return_arr[] = array(
"command" => 'success',
"process" => "change_temperature",
"temperature" => $temperature
);
print("TEMP CHANGED");
break; // case 'change_temperature'
case 'change_freq_penalty':
$freq_penalty = $_POST['flds']['freq_penalty'];
$_SESSION['freq_penalty'] = $freq_penalty;
$return_arr[] = array(
"command" => 'success',
"process" => "change_freq_penalty",
"freq_penalty" => $freq_penalty
);
break; // case 'change_freq_penalty'
case 'change_pres_penalty':
$pres_penalty = $_POST['flds']['pres_penalty'];
$_SESSION['pres_penalty'] = $pres_penalty;
$return_arr[] = array(
"command" => 'success',
"process" => "change_pres_penalty",
"pres_penalty" => $pres_penalty
);
break; // case 'change_pres_penalty'
case 'change_max_tokens':
$max_tokens = $_POST['flds']['max_tokens'];
$_SESSION['max_tokens'] = $max_tokens;
$return_arr[] = array(
"command" => 'success',
"process" => "change_max_tokens",
"max_tokens" => $max_tokens
);
break; // case 'change_max_tokens'
case 'reset_messages':
$_SESSION['messages'] = [];
$return_arr[] = array(
"command" => 'success',
"process" => "reset_messages"
);
$return_arr[] = array(
"command" => 'html',
'selector' => '.output',
'msg' => html_messages($_SESSION['messages'])
);
break; // case 'reset_messages'
} // end switch($_GET['ajax'])
if(!empty($return_arr) && is_array($return_arr))
die(json_encode($return_arr));
die();
} // end if(!empty($_GET['ajax']))
?>
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script>
// BEGIN --> JAVASCRIPT COMMAND PROCESSOR //
function do_cmd_post(url, send_data)
{
$.post( url, { flds: send_data /* in php will appear as $_POST['flds'] */ },
function( return_data ) {
do_cmd_process(return_data);
}, "json" ); // punt any returned data to processor
}
// ---
function do_cmd_process(data) // handle data coming back from ajax
{
if (data instanceof Array) {
data.forEach(function(entry) {
console.log(entry.command);
//console.log(entry.message);
// handle returned commands //
switch(entry.command)
{
// generic commands //
case 'alert':
alert(entry.msg);
break;
case 'log':
console.log(entry.msg);
break;
case 'append':
$(entry.selector).append(entry.msg);
break;
case 'prepend':
$(entry.selector).prepend(entry.msg);
break;
case 'html':
$(entry.selector).html(entry.msg);
break;
case 'val':
$(entry.selector).val(entry.msg);
break;
case 'focus':
$(entry.selector).focus();
break;
case 'blur':
$(entry.selector).blur();
break;
case 'clear':
$(entry.selector).val('');
break;
case 'js':
eval(entry.msg);
break;
case 'resize_textarea_to_fit_contents':
$(entry.selector).height(0);
$(entry.selector).height($(entry.selector)[0].scrollHeight);
break;
case 'disable_input':
$(entry.selector).prop('disabled', true);
break;
case 'enable_input':
$(entry.selector).prop('disabled', false);
break;
case 'resize_textareas':
$(".message_content textarea").each(function(){
$(this).css("height", ($(this).prop("scrollHeight")) + "px");
});
break;
} // end : switch (entry.command)
}); // end : data.forEach(function(entry)
} // end : if (data instanceof Array)
} // end : function do_cmd_process(data)
// END --> JAVASCRIPT COMMAND PROCESSOR //
</script>
</head>
<body>
<br /><br />
<?php
?>
<div class='output' id="output" style='width: 100%; overflow: scroll; border: 1px solid #000;'><?php echo html_messages($_SESSION['messages']); ?></div>
<div class='row'>
<input type='text' name='save-message_title' id='save-message_title' value='' placeholder='Save Conversation Title' />
<input type='button' value='Save Conversation' onclick='btn_save_conversation();' />
<?php echo html_conversation_combobox(); ?>
<input type='button' value='Load Conversation' onclick='btn_load_conversation();' />
<input type='button' value='Delete Conversation' onclick='btn_delete_conversation();' />
<input type='button' value='Reset Conversation' onclick='btn_reset_messages();' />
</div>
<br />
<br />
<textarea name="text_agent" id='text_agent'
onchange="btn_change_agent();"
style='width: 100%; height: 100px; overflow: scroll; border: 1px solid #000;'
><?php echo $_SESSION['agent']; ?></textarea>
<div class='row'>
<input type='text' name='save-agent_title' id='save-agent_title' value='' placeholder='Save Agent Title' />
<input type='button' value='Save Agent' onclick='btn_save_agent();' />
<?php echo html_agents_combobox(); ?>
<input type='button' value='Load Agent' onclick='btn_load_agent();' />
<input type='button' value='Update Agent' onclick='btn_change_agent();' />
<input type='button' value='Delete Agent' onclick='btn_delete_agent();' />
</div>
<br /><br />
<textarea name="text_prompt" style='width: 100%; height: 100px; overflow: scroll; border: 1px solid #000;'></textarea>
<input type='button' id='send-button' value='Send Prompt' onclick='btn_send_prompt();' />
<br /><br />
<!-- a combo box to select between gpt-3.5-turbo and gpt-4 -->
<select id="model" name="model" onchange="btn_change_model();">
<option value="gpt-3.5-turbo" <?php if($_SESSION['model']=="gpt-3.5-turbo") echo "SELECTED" ?> >gpt-3.5-turbo</option>
<option value="gpt-3.5-turbo-16k" <?php if($_SESSION['model']=="gpt-3.5-turbo-16k") echo "SELECTED" ?> >gpt-3.5-turbo-16k</option>
<option value="gpt-4" <?php if($_SESSION['model']=="gpt-4") echo "SELECTED" ?>>gpt-4</option>
<option value="gpt-4-32k" <?php if($_SESSION['model']=="gpt-4-32k") echo "SELECTED" ?>>gpt-4-32k</option>
</select>
<script>
function btn_delete_agent()
{
// confirm delete //
if(!confirm('Are you sure you want to delete this agent?'))
return;
var send_data = {
"file": $('select[name="agents_combobox"]').val()
};
do_cmd_post('example.phpopenaichat.php?ajax=delete_agent', send_data);
}
function btn_save_agent()
{
// data already on server so just send a title.
var send_data = {
"title": $('input[name="save-agent_title"]').val()
};
do_cmd_post('example.phpopenaichat.php?ajax=save_agent', send_data);
}
function btn_load_agent()
{
var send_data = {
"file": $('select[name="agents_combobox"]').val()
};
do_cmd_post('example.phpopenaichat.php?ajax=load_agent', send_data);
}
function btn_delete_conversation()
{
// confirm delete
if(!confirm('Are you sure you want to delete this conversation?'))
return;
var send_data = {
"file": $('select[name="conversation_combobox"]').val()
};
do_cmd_post('example.phpopenaichat.php?ajax=delete_conversation', send_data);
}
function btn_load_conversation()
{
var send_data = {
"file": $('select[name="conversation_combobox"]').val()
};
do_cmd_post('example.phpopenaichat.php?ajax=load_conversation', send_data);
}
function btn_save_conversation()
{
// data already on server so just send a title.
// if title empty, alert and abort.
if($('input[name="save-message_title"]').val()=='')
{
alert('Please enter a title for this conversation.');
return;
}
var send_data = {
"title": $('input[name="save-message_title"]').val()
};
do_cmd_post('example.phpopenaichat.php?ajax=save_conversation', send_data);
}
function btn_send_prompt()
{
// disable #send-button
$('#send-button').prop('disabled', true);
// confirm
if(!confirm('Are you sure you want to send this prompt?'))
{
$('#send-button').prop('disabled', false);
return;
}
var send_data = {
"prompt": $('textarea[name="text_prompt"]').val(),
};
do_cmd_post('example.phpopenaichat.php?ajax=prompt', send_data);
}
function btn_change_agent()
{
// confirm changes
if(!confirm('Are you sure you want to change the agent on the server? (server must have an agent sent for it to process an agent)'))
return;
var send_data = {
"agent": $('textarea[name="text_agent"]').val(),
};
do_cmd_post('example.phpopenaichat.php?ajax=change_agent', send_data);
}
function btn_change_model()
{
var send_data = {
"model": $('select[name="model"]').val(),
};
do_cmd_post('example.phpopenaichat.php?ajax=change_model', send_data);
}
function btn_change_temp()
{
var send_data = {
"temperature": $('input[name="temperature"]').val(),
};
do_cmd_post('example.phpopenaichat.php?ajax=change_temperature', send_data);
}
function btn_change_freq_penalty()
{
var send_data = {
"freq_penalty": $('input[name="freq_penalty"]').val(),
};
do_cmd_post('example.phpopenaichat.php?ajax=change_freq_penalty', send_data);
}
function btn_change_pres_penalty()
{
var send_data = {
"pres_penalty": $('input[name="pres_penalty"]').val(),
};
do_cmd_post('example.phpopenaichat.php?ajax=change_pres_penalty', send_data);
}
function btn_reset_messages()
{
var send_data = {
"reset_messages": 1,
};
do_cmd_post('example.phpopenaichat.php?ajax=reset_messages', send_data);
}
function btn_max_tokens()
{
var send_data = {
"max_tokens": $('input[name="max_tokens"]').val(),
};
do_cmd_post('example.phpopenaichat.php?ajax=change_max_tokens', send_data);
}
function btn_edit_in_place()
{
/*
$html .= '<div class="message" row_count="'+$row_count+'" >';
$html .= '<div class="message_role">'.$message['role'].'</div>';
$html .= '<div class="message_content" onclick="btn_edit_in_place();">'.$message['content'].'</div>';
$html .= '</div>';
*/
/* swap out the div with a textarea */
var row_count = 1;
var message_content = $('div.message_content[row_count="'+row_count+'"]').html();
$('div.message_content[row_count="'+row_count+'"]').html('<textarea name="message_content" row_count="'+row_count+'" style="width: 100%; height: 100px; overflow: scroll; border: 1px solid #000;">'+message_content+'</textarea>');
}
function btn_update_message_content(that)
{
the_row = $(that).attr('row_count');
the_msg = $(that).val();
// var row_count = $('textarea[name="message_content"]').attr('row_count');
// var message_content = $('textarea[name="message_content_textarea"]').val();
// alert(the_msg);
// alert(the_row);
var send_data = {
"row_count": the_row,
"message_content": the_msg,
};
// get user confirmation to continue
if(confirm("Are you sure you want to update the message content?"))
{
do_cmd_post('example.phpopenaichat.php?ajax=change_message_content', send_data);
} else {
alert("reload page to restore original message content.");
}
}
</script>
<br /><br />
<!-- a slider to select temperature -->
<label for="temperature">Temperature</label>
<input type="range" id="temperature" onchange="btn_change_temp();" name="temperature" min="0.0" max="2.0" step="0.1" value="<?php echo $_SESSION["temperature"] ?>">
<div id="temperature_value"></div>
<!-- a slider to select frequency penalty -->
<label for="freq_penalty">Frequency Penalty</label>
<input type="range" id="freq_penalty" onchange="btn_change_freq_penalty();" name="freq_penalty" min="0.0" max="1.0" step="0.1" value="<?php echo $_SESSION["freq_penalty"] ?>">
<div id="freq_penalty_value"></div>
<!-- a slider to select presence penalty -->
<label for="pres_penalty">Presence Penalty</label>
<input type="range" id="pres_penalty" onchange="btn_change_pres_penalty();" name="pres_penalty" min="0.0" max="1.0" step="0.1" value="<?php echo $_SESSION["pres_penalty"] ?>">
<div id="pres_penalty_value"></div>
<!-- a text input to select max tokens -->
<label for="max_tokens">Max Tokens</label>
<input type="number" id="max_tokens" onchange="btn_max_tokens();" name="max_tokens" min="1" max="100" value="<?php echo $_SESSION["max_tokens"] ?>">
<br /><br />
<!-- reset messages button -->
<input type='button' value='Reset Messages' onclick='btn_reset_messages();' />
<br /><br />
<!-- jquery to add a div under the sliders to show the current value of the sliders. -->
<script>
$(document).ready(function(){
$('#temperature_value').html($('#temperature').val());
$('#freq_penalty_value').html($('#freq_penalty').val());
$('#pres_penalty_value').html($('#pres_penalty').val());
});
</script>
<!-- jquery to update the divs when the sliders are moved -->
<script>
$(document).ready(function(){
$('#temperature').on('input', function() {
$('#temperature_value').html($('#temperature').val());
});
$('#freq_penalty').on('input', function() {
$('#freq_penalty_value').html($('#freq_penalty').val());
});
$('#pres_penalty').on('input', function() {
$('#pres_penalty_value').html($('#pres_penalty').val());
});
});
</script>
<pre>
<?php
// print_r($_SESSION['messages']);
?>
</pre>
<script>
// make tab character act like a normal tab character in textareas
$(document).delegate('textarea', 'keydown', function(e) {
var keyCode = e.keyCode || e.which;
if (keyCode == 9) {
e.preventDefault();
var start = $(this).get(0).selectionStart;
var end = $(this).get(0).selectionEnd;
// set textarea value to: text before caret + tab + text after caret
$(this).val($(this).val().substring(0, start)
+ "\t"
+ $(this).val().substring(end));
// put caret at right position again
$(this).get(0).selectionStart =
$(this).get(0).selectionEnd = start + 1;
}
});
</script>
<script>
// javascript to handle expanding textarea to fit content height whenever focus is on it and user is typing
$(document).ready(function(){
// $(".message_content textarea").css("height", "auto");
// set each textarea on load to the size of its contents in the .messages area
$(".message_content textarea").each(function(){
$(this).css("height", ($(this).prop("scrollHeight")) + "px");
});
// handle dynamic loaded divs
$(".message_content textarea").on("focus", function(){
// $(this).css("height", "auto");
$(this).css("height", ($(this).prop("scrollHeight")) + "px");
});
$(".message_content textarea").on("blur", function(){
// $(this).css("height", "auto");
$(this).css("height", ($(this).prop("scrollHeight")) + "px");
});
$(".message_content textarea").on("change", function(){
// $(this).css("height", "auto");
$(this).css("height", ($(this).prop("scrollHeight")) + "px");
});
// $(".message_content textarea").on("keyup", function(){
// $(this).css("height", "auto");
// // $(this).css("height", ($(this).prop("scrollHeight")) + "px");
// });
});
</script>
<style>
.messages {
}
.message {
border-bottom: 3px solid red;
}
.message.even {
background-color: #eee;
}
.message_content {
padding:3vw;
}
</style>
<!-- one shot section -->
<hr />
<?php
function one_shot($api_key, $prompt, $agent='You are a helpful assistant.', $temperature=1.0, $max_tokens=4000, $model="gpt-3.5-turbo")
{
$temperature = (float) round($temperature,1);
$max_tokens = (int) $max_tokens;
// if $prompt empty return '' else get response and return the text...
$messages = [];
$AIChat = new PHPOpenAIChat($api_key);
$AIChat->model = $model;
$AIChat->temperature = $temperature;
$AIChat->set_max_tokens($max_tokens);
$AIChat->set_agent($messages, $agent);
$messages = $AIChat->add_prompt_to_messages($messages, $prompt);
if (empty($prompt))
return '';
else
{
$response = $AIChat->sendMessage($messages);
$text = $AIChat->get_response_text($response);
// print_r($response);
return $text;
}
} // end one_shot()
?>
<style>
.one_shot {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-gap: 1vw;
}
.one_shot .col {
padding: 1vw;
}
.one_shot textarea {
width: 100%;
height: 10vw;
}
.one_shot input {
width: 100%;
}
</style>
<div class='title'>One Shot Section - Enter a prompt and get a single one-off response</div>
<div class='one_shot'>
<div class='col'><textarea class='prompt' name='prompt' id='prompt' placeholder='prompt'></textarea></div>
<div class='col'><textarea class='agent' name='agent' id='agent' placeholder='agent'></textarea></div>
<div class='col'><textarea class='response' name='response' id='response' placeholder='response'></textarea></div>
<!-- model combo box -->
<!-- a combo box to select between gpt-3.5-turbo and gpt-4 -->
<select id="model" name="model" onchange="btn_change_model();">
<option value="gpt-3.5-turbo" <?php if($_SESSION['model']=="gpt-3.5-turbo") echo "SELECTED" ?> >gpt-3.5-turbo</option>
<option value="gpt-4" <?php if($_SESSION['model']=="gpt-4") echo "SELECTED" ?>>gpt-4</option>
</select>
<div class='col'><input type='text' class='temperature' name='temperature' id='temperature' placeholder='temperature' value='1.0' /></div>
<div class='col'><input type='button' class='the-button' value='One Shot' onclick='btn_one_shot();' /></div>
</div><!-- end one shot section -->
<script>
function btn_one_shot()
{
var send_data = {
"prompt": $('textarea[name="prompt"]').val(),
"agent": $('textarea[name="agent"]').val(),
"temperature": $('input[name="temperature"]').val(),
"max_tokens": $('input[name="max_tokens"]').val(),
"model": $('select[name="model"]').val(),
};
// disable #send-button
$('.one_shot .the-button').prop('disabled', true);
do_cmd_post('example.phpopenaichat.php?ajax=one-shot', send_data);
}
</script>
</body>
</html>
|