Hello and thank you for sharing! Iām glad to see this product as a browser extension where it can be in quick reach.
This project promises to offer quick answers for questions about TRON apps and documentation.
The main thing that is missing is that it is not streaming the responses to the client as they are generated by (Iām assuming, OpenAI). This means that the responses appear to be āslowerā as they are all presented at once. I know this is a pain. I implemented this too, my code is below.
Keep it up, and glad to see this contribution
/**
* Run the hydrated messages.
*
* Using: https://platform.openai.com/docs/guides/chat
*
* @return void
*/
private function runHydratedMessages(): void
{
$fullResponse = '';
$responseBuffer = '';
$handlePartialOutput = $this->handlePartialOutput;
$responseStreamingHandler = function ($curlHandle, $responseBody) use (&$responseBuffer, &$fullResponse, $handlePartialOutput) {
$retval = strlen($responseBody);
$responseBuffer .= $responseBody;
if (strpos($responseBuffer, "\n\n") === false) {
return $retval;
}
$responseParts = explode("\n\n", $responseBuffer);
$responseBuffer = array_pop($responseParts);
foreach ($responseParts as $event) {
// Only process data event
if (!str_starts_with($event, 'data: ')) {
continue;
}
$responsePart = substr($event, strlen('data: '));
if (strlen($responsePart) === 0) {
continue;
}
if ($responsePart === '[DONE]') {
continue;
}
$responseObject = json_decode($responsePart);
if ($responseObject->choices[0]->finish_reason !== null) {
continue;
}
// data: {"id":"chatcmpl-7pcDx6jP42vi9Yk40hTXmD8IYCgKR","object":"chat.completion.chunk","created":1692059361,"model":"gpt-3.5-turbo-0613","choices":[{"index":0,"delta":{"content":"202"},"finish_reason":null}]}
// call $handlePartialOutput
$handlePartialOutput($responseObject->choices[0]->delta->content);
$fullResponse .= $responseObject->choices[0]->delta->content;
}
return $retval;
};
$curlHandle = curl_init();
curl_setopt_array($curlHandle, [
CURLOPT_URL => 'https://api.openai.com/v1/chat/completions',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode([
'model' => 'gpt-3.5-turbo',
'messages' => $this->hydratedMessages,
'stream' => true,
]),
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . self::API_KEY,
'Content-Type: application/json',
],
CURLOPT_WRITEFUNCTION => $responseStreamingHandler,
// CURLOPT_HEADER => true, // get response headers
]);
$response = curl_exec($curlHandle);
$info = curl_getinfo($curlHandle);
// $responseBody = substr($response, $info['header_size']);
// $responseHeaders = substr($response, 0, $info['header_size']);
// process result
// $responseObject = json_decode($responseBody);
// $this->debug->run = $responseObject;
$this->debug->info = $info;
$this->debug->fullResponse = $fullResponse;
$this->cost = strlen($fullResponse) * self::PRICE_PER_THOUSAND_BYTES / 1000;
$this->output = $fullResponse;
// todo: where to handle errors?
// to test: insufficient funds
// to test: to many requests/taken too long
// to test: invalid key
// to test: unsavory input
}