Rollback to OpenAI API

This commit is contained in:
Thommy Bucaille 2024-04-06 01:17:49 +02:00
parent 56f22c1b58
commit efe9d2bd49
2 changed files with 74 additions and 122 deletions

View File

@ -13,7 +13,7 @@ use Mails\CustomEmail;
use Models\Memory;
use Models\User;
use OpenAI;
use OpenAI\Responses\Chat\CreateResponse;
use OpenAI\Responses\Chat\CreateStreamedResponse;
use Symfony\Component\HttpClient\HttpClient;
class ChatController extends BaseController
@ -104,19 +104,18 @@ class ChatController extends BaseController
foreach ($r->choices as $data) {
$allowed_role = ['user', 'system', 'assistant', 'tool'];
if (!in_array($data->message->role, $allowed_role)) continue;
if (!in_array($data->delta->role, $allowed_role)) continue;
if ($data->message->role == 'tool') {
if ($data->delta->role == 'tool' || !empty($data->delta->toolCalls)) {
self::$context_messages[] = [
'tool_call_id' => $data->tool_call_id,
'name' => $data->message->name,
'role' => $data->message->role,
'content' => $data->message->content,
'toolCalls' => $data->delta->toolCalls,
'role' => $data->delta->role,
'content' => $data->delta->content,
];
} else {
self::$context_messages[] = [
'role' => $data->message->role,
'content' => $data->message->content,
'role' => $data->delta->role,
'content' => $data->delta->content,
];
}
}
@ -152,20 +151,20 @@ class ChatController extends BaseController
{
try {
// self::$client = OpenAI::client(config('chat.key'));
// self::$client = OpenAI::factory()
// ->withBaseUri(config("chat.base_uri", "api.openai.com/v1"))
// ->withApiKey(config('chat.key'))
// ->withHttpClient($client = new \GuzzleHttp\Client([])) // default: HTTP client found using PSR-18 HTTP Client Discovery
// ->withHttpHeader('OpenAI-Beta', 'assistants=v1')
// ->make();
self::$client = new \GuzzleHttp\Client([
'base_uri' => config("chat.base_uri", "https://api.openai.com/v1"),
"headers" => [
"Authorization" => "Bearer " . config('chat.key'),
'accept' => 'application/json',
'Content-Type' => 'application/json',
]
]);
self::$client = OpenAI::factory()
// ->withBaseUri(config("chat.base_uri", "api.openai.com/v1"))
->withApiKey(config('chat.key'))
->withHttpClient($client = new \GuzzleHttp\Client([])) // default: HTTP client found using PSR-18 HTTP Client Discovery
->withHttpHeader('OpenAI-Beta', 'assistants=v1')
->make();
// self::$client = new \GuzzleHttp\Client([
// 'base_uri' => config("chat.base_uri", "https://api.openai.com/v1"),
// "headers" => [
// "Authorization" => "Bearer " . config('chat.key'),
// 'accept' => 'application/json',
// 'Content-Type' => 'application/json',
// ]
// ]);
if (!Helper::isCLI()) {
@ -650,99 +649,65 @@ class ChatController extends BaseController
}
self::$NB_REQUEST++;
// $result = self::$client->chat()->create([
// 'model' => config('chat.model'),
// 'messages' => (array)self::$context_messages,
// 'tools' => (array)self::$tools,
// 'user' => Helper::isCLI() ? "system" : Auth::user()->username,
// ]);
$stream = self::$client->chat()->createStreamed([
'model' => config('chat.model'),
'messages' => (array)self::$context_messages,
'tools' => (array)self::$tools,
'user' => Helper::isCLI() ? "system" : Auth::user()->username,
]);
ob_implicit_flush(1); // Enable implicit flush
ob_end_flush(); // Flush the buffer
// Use guzzle HTTP directly
$response = self::$client->post('v1/completions', [
'stream' => true,
'timeout' => 0,
'json' => [
'model' => config('chat.model'),
// 'messages' => (array)self::$context_messages,
// 'tools' => (array)self::$tools,
// 'user' => Helper::isCLI() ? "system" : Auth::user()->username,
"prompt" => implode("\n", array_map(function ($message) {
$text = "";
if ($message['role'] === "user") {
if (Auth::check()) {
$text = "### Instruction:\n" . Auth::user()->username . ": ";
} else {
$text = "### Instruction:\n";
}
} elseif ($message['role'] === "system") {
$text = "### Context:\n";
} elseif ($message['role'] === "assistant") {
$text = "### Response:\n";
} // elseif TODO Handle tool
// Clean extra whitespaces
$message['content'] = preg_replace('/\s+/', ' ', trim($message['content']));
$text .= $message['content'];
return $text;
}, self::$context_messages)) . "\n### Response:\nScotty: ",
"max_tokens" => 150,
"temperature" => 0.5,
"top_p" => 0.3,
"top_k" => 20,
"n" => 1,
"stream" => true,
"repeat_penalty" => 1.8
]
]);
$body = $response->getBody();
$jsonBuffer = '';
$concatened_final_data = null;
foreach($stream as $chunk) {
while (!$body->eof()) {
$chunk = $body->read(1024);
$jsonBuffer .= $chunk;
// Each chunk return data like:
// data: (json object)
// Each new "data:" prefix is a new chunk of data
// So we can split the buffer by "data:" to get each json object
// also each chunk can have multiple json objects, so we can split by "\n" to get each json object
// or incomplete json object
// Convert to object
$chunk = (object)(array) $chunk;
foreach($chunk->choices as &$choice) {
$choice = (object)(array) $choice;
$choice->delta = (object)(array) $choice->delta;
$choice->delta->toolCalls = (array) $choice->delta->toolCalls;
foreach($choice->delta->toolCalls as &$toolCall) {
$toolCall = (object)(array) $toolCall;
$toolCall->function = (object)(array) $toolCall->function;
}
}
$jsonObjects = explode("data: ", $jsonBuffer);
foreach ($jsonObjects as $jsonObject) {
$baseJsonObject = $jsonObject;
if (empty($jsonObject)) continue;
$jsonObject = json_decode($jsonObject, true);
if (empty($jsonObject)) continue;
$result = $this->handleResponse($jsonObject);
if(empty($concatened_final_data)) {
$concatened_final_data = $result;
} else {
$concatened_final_data[0]->choices[0]->text .= $result[0]->choices[0]->text;
if(empty($concatened_final_data)) {
$concatened_final_data = $chunk;
} else {
if(!empty($chunk->choices[0]->delta->role)) {
$concatened_final_data->choices[0]->delta->role .= $chunk->choices[0]->delta->role;
}else{
$chunk->choices[0]->delta->role = $concatened_final_data->choices[0]->delta->role;
}
// Traiter l'objet JSON
$streamResponse = "::end:: " . json_encode([
'success' => true,
'stream' => true,
'id' => $jsonObject['id'],
'result' => $result,
]) . " ";
if(!empty($concatened_final_data->choices[0]->delta->content)) {
$concatened_final_data->choices[0]->delta->content .= $chunk->choices[0]->delta->content;
}
echo $streamResponse;
// For each toolsCalls, we need to merge the data
foreach($chunk->choices[0]->delta->toolCalls as $toolCallIndex => $toolCall) {
if(!empty($concatened_final_data->choices[0]->delta->toolCalls[$toolCallIndex])) {
$concatened_final_data->choices[0]->delta->toolCalls[$toolCallIndex]->function->arguments .= $toolCall->function->arguments;
} else {
$concatened_final_data->choices[0]->delta->toolCalls[] = $toolCall;
}
}
// Remove the data json object from the buffer
$jsonBuffer = str_replace("data: " . $baseJsonObject, "", $jsonBuffer);
$concatened_final_data->choices[0]->finishReason .= $chunk->choices[0]->finishReason;
}
$streamResponse = "::end:: " . json_encode([
'success' => true,
'stream' => true,
'id' => $chunk->id,
'result' => [$chunk],
]) . " ";
echo $streamResponse;
}
return $this->handleResponse($concatened_final_data);
@ -754,25 +719,11 @@ class ChatController extends BaseController
private function handleResponse($response)
{
if (empty($response) || !is_array($response)) {
if (empty($response)) {
return [];
}
$message = $response['choices'][0]['text'];
return [
(object)[
"choices" => [
(object)[
"message" => (object)[
"role" => "assistant",
"content" => $message,
]
]
]
]
];
// TODO: Handle tool
$message = $response->choices[0]->delta;
$results = [];
if ($message) {

View File

@ -241,6 +241,7 @@ View::set('title', __('home'));
// Then parse each message
// Splitting the chunk into messages
console.log(textDecoder.decode(value));
const json_responses = (textDecoder.decode(value)).split('::end::');
// Parsing each message
@ -286,8 +287,8 @@ View::set('title', __('home'));
const messageId = data.id;
data.result.forEach((r) => {
r.choices.forEach((data) => {
if (data.message && data.message.content) {
currentCloneMessage = addMessage(data.message.role, data.message.content, messageId);
if (data.delta.content && data.delta.content) {
currentCloneMessage = addMessage(data.delta.role, data.delta.content, messageId);
}
});
});