I manage to write a PHP script that accept a question and return answer.
It design to work with Assistants.
The idea is that you’ll create and tune assistant at the web interface - no code is needed. Than you can interact with it through this script. You can chat it from a browser.
Here we go:
<?PHP
/*
Wrote it: Tal Bahir.
This scrip runs from the console.
It take 1 parameter.
Example: php chatgpt.php "What you want to know"
To use it, create an assistant with vectore store if needed.
Put the assistant ID in the proper vaiable below
*/
//Yes/No if called from a browser or console
$runAsScript=(PHP_SAPI==='cli');
$previousTime = microtime(true);
// Variable to count the step number
$stepCounter = 0;
//If true will echo steps time
$lShowStepsTime=false;
if ($runAsScript)
{
session_id('runQueryToAssistant');
}
session_start();
//Set to 1 to create new thread every run. Otherwise - reuse existing thread.)
if (0)
{
session_destroy();
// session_unset();
// die();
}
//If true you can attach vector store. No need if already have it in your own Assistant
$useVectorStors=false;
$returnHTML=true;
$cQuery=isset($argv[1])?$argv[1]:'Put a question here';
if ($runAsScript)
{
echo "\nAsking Chatboot: $cQuery\n";
}
$OPENAI_API_KEY="Your API KEY HERE";
//Your already ready assistant ID:
$ASST_ID="Your assistant ID here";
$VS_ID="If you have vector stor, you can put here Optional";
$FILESRCH_ID="Your search file here. Optional";
$THRD_ID=(isset($_SESSION['THRD_ID'])?$_SESSION['THRD_ID']:'');
$MSG_ID="";
$RUN_ID="";
$headers = [
"Authorization: Bearer $OPENAI_API_KEY",
'Content-Type: application/json',
'Accept: application/json',
"OpenAI-Beta: assistants=v2"
];
//Check if thread exists:
$url="https://api.openai.com/v1/threads/$THRD_ID";
$thread=json_decode(get_content($url,$nTO=30,$post=1,false,'',$headers),true);
echoStep('Check if thread exists');
//Check for errors
check_error($thread);
//If thread not exists create new one.
if (!$THRD_ID||!$thread['id'])
{//Create new thread
$url="https://api.openai.com/v1/threads";
//With Vector Store
if ($useVectorStors)// for thread without vector store
{//Thread WITH vectore store
$thread=json_decode(get_content($url,$nTO=30,$post=1,$userPass=false,'{
"tool_resources": {
"file_search": {
"vector_store_ids": ["'.$VS_ID.'"]
}
}
}',$headers),true);
/*KEEP - In case wnat to attach vector_store:
$thread=json_decode(get_content($url,$nTO=30,$post=1,$userPass=false,'{
"tool_resources": {
"file_search": {
"vector_stores":
[
{"file_ids": ["'.$FILESRCH_ID.'"]}
]
}
}
}',$headers),true);
*/
}
else
{//Thread without vectore store
$thread=json_decode(get_content($url,$nTO=30,$post=1,$userPass=false,'',$headers),true);
}
echoStep('Thread created');
//Check for errors
check_error($thread);
$THRD_ID=$thread['id'];
$_SESSION['THRD_ID']=$THRD_ID;
}
else
{//Thread exists
$THRD_ID=$_SESSION['THRD_ID'];
echoStep('Thread reused');
}
//die(print_r($thread));
//Create a message:
$url="https://api.openai.com/v1/threads/$THRD_ID/messages";
$payload = json_encode(
[
"role" => "user",
"content" => $cQuery
]);
$message=json_decode(get_content($url,$nTO=30,$post=1,$userPass=false,$payload,$headers),true);
echoStep('Message created');
//Check for errors
check_error($message);
$MSG_ID=$message['id'];
//Create run:
$url="https://api.openai.com/v1/threads/$THRD_ID/runs";
$run=json_decode(get_content($url,$nTO=30,$post=1,$userPass=false,'{
"assistant_id": "'.$ASST_ID.'",
"tool_choice":"required",
"tools":
[
{"type": "file_search"}
]
}',$headers),true);
echoStep('Run created');
/*
$run=json_decode(get_content($url,$nTO=30,$post=1,$userPass=false,'{
"assistant_id": "'.$ASST_ID.'"
}',$headers),true);
*/
//Check for errors
check_error($run);
$RUN_ID=$run['id'];
//Wait for the run's completion
$url="https://api.openai.com/v1/threads/$THRD_ID/runs/$RUN_ID";
$nLoops=10;
while ($nLoops>0)
{//Wait for completion
sleep(4);
$status=json_decode(get_content($url,$nTO=30,$post=0,$userPass=false,'',$headers,$writeCallback),true);
check_error($status);
echoStep("Run loop# $nLoops . Status: $status[status]");
if ($status['status']=='completed')
{
break;
}
$nLoops--;
}
if ($nLoops==0)
{
die(json_encode(["error"=>"Timeout waiting for the run completion"]));
}
echoStep('Run completed');
//Get messages:
$url="https://api.openai.com/v1/threads/$THRD_ID/messages";
$output=get_content($url,$nTO=30,$post=0,$userPass=false,'',$headers);
$messages=json_decode($output,true);
//Check for errors
check_error($message);
echoStep('Message retrieved');
//Loop thrugh the messages to find the last run's answer
$lMsgFound=false;
foreach($messages as $msgs)
{
if (is_array($msgs))
{
foreach($msgs as $msg)
{
if ($msg['run_id']==$RUN_ID)
{
$lMsgFound=true;
break;
}
}
}
if ($lMsgFound)
{
break;
}
}
if ($lMsgFound)
{
/*Create embedding*/
echoStep('Message found and ready');
$headers=
[
"Authorization: Bearer $OPENAI_API_KEY",
"Content-Type: application/json"
];
$data=json_encode(
[
"input" => $cQuery, // Your question
"model" => "text-embedding-ada-002" // Example embedding model
]);
$response=json_decode(get_content("https://api.openai.com/v1/embeddings",30,0,false,$data,$headers),true);
check_error($response);
$embeddingString=json_encode($response['data'][0]['embedding']);
/*Create embedding end*/
$cMsg=$msg['content'][0]['text']['value'];
$cMsg=json_encode(["results"=>($returnHTML?convertToHTML($cMsg):$cMsg),"error"=>"","embedding"=>$embeddingString]);
}
else
{
echoStep('Message NOT found');
$cMsg=json_encode(["error"=>"Could not find the answer for the last question","results"=>"","embedding"=>""]);
}
echoStep('Request completed');
if ($runAsScript)
{//Show from script
$cMsg=json_decode($cMsg,true);
die("\nChatboot: $cMsg[results]\n"."\nIt has a ".strlen($cMsg['embedding'])." characters in embedding code\n");
}
else
{//Send json string to browser:
die("$cMsg\n");
}
//Functions:
function check_error($response)
{
if (isset($response['error']))
{
die(json_encode(["error" => $response['error']['message']]));
}
}
function get_content($url,$nTO=30,$post=0,$userPass=false,$payLoad=false,$headers=false,$writeFunction=null)
{//
//$userPass example: -u 'SK165acdc14eb71bbc07fb8b66dDdD84a64ce:1jSDdDVmW9EDcKUNz7NpFWKm1QZwHC01s9h'
//$payLoad example:['From' => '+122344444','To' => '+13101111111','Body' => 'This is the body...']
$url = str_replace(" ", "%20", $url);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT,$nTO);
curl_setopt($ch, CURLOPT_POST,$post);
if ($userPass)
{
curl_setopt($ch, CURLOPT_USERPWD,$userPass);
}
if ($headers)
{
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
}
if ($payLoad)
{
curl_setopt($ch, CURLOPT_POSTFIELDS,$payLoad);
}
$string=curl_exec($ch);
$getcode=curl_getinfo($ch,CURLINFO_HTTP_CODE);
if (!$string)
{
$string='ERR: '.curl_errno($ch).'. Problem is: '.curl_strerror(curl_errno($ch)).".<br>Likley - target not found.<br>URL: $url";
}
if ($getcode!=200&&curl_errno($ch)!='0'&&$getcode!='0')
{
$string="ERR: Not found. $getcode<br>URL: $url";
}
curl_close($ch);
return $string;
}
function convertToHTML($response)
{
// Replace newline characters with <br> for HTML line breaks
$response = nl2br($response);
// Convert dashes used for lists into HTML unordered list
$response = preg_replace('/\n-\s(.+)/', '<li>$1</li>', $response);
// Wrap list items in <ul> tags
$response = preg_replace('/(<li>.*<\/li>)/s', '<ul>$1</ul>', $response);
// Return the resulting HTML
return $response;
}
function echoStep($message='')
{
global $previousTime,$stepCounter,$runAsScript,$lShowStepsTime;
if (!$runAsScript||!$lShowStepsTime) {return;}
$stepCounter++;
$currentTime = microtime(true);
$timeTaken = $currentTime - $previousTime;
$previousTime = $currentTime;
//Show elaps time
//echo "$message. Step $stepCounter. Elaps time: " . number_format($elapsedTime, 2) . " seconds\n";
//Show step time
echo "Step $stepCounter: Step's time: " . number_format($timeTaken, 2) . " seconds. $message\n";
}
?>