upgrade
This commit is contained in:
91
plugin/ai_helper/src/deepseek/DeepSeek.php
Normal file
91
plugin/ai_helper/src/deepseek/DeepSeek.php
Normal file
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
/* For license terms, see /license.txt */
|
||||
|
||||
require_once 'DeepSeekUrl.php';
|
||||
|
||||
class DeepSeek
|
||||
{
|
||||
private $apiKey;
|
||||
private $headers;
|
||||
|
||||
public function __construct(string $apiKey)
|
||||
{
|
||||
$this->apiKey = $apiKey;
|
||||
$this->headers = [
|
||||
'Content-Type: application/json',
|
||||
"Authorization: Bearer {$this->apiKey}",
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate questions using the DeepSeek API.
|
||||
*
|
||||
* @param array $payload Data to send to the API
|
||||
*
|
||||
* @throws Exception If an error occurs during the request
|
||||
*
|
||||
* @return string Decoded response from the API
|
||||
*/
|
||||
public function generateQuestions(array $payload): string
|
||||
{
|
||||
$url = DeepSeekUrl::completionsUrl();
|
||||
$response = $this->sendRequest($url, 'POST', $payload);
|
||||
|
||||
if (empty($response)) {
|
||||
throw new Exception('The DeepSeek API returned no response.');
|
||||
}
|
||||
|
||||
$result = json_decode($response, true);
|
||||
|
||||
// Validate errors returned by the API
|
||||
if (isset($result['error'])) {
|
||||
throw new Exception("DeepSeek API Error: {$result['error']['message']}");
|
||||
}
|
||||
|
||||
// Ensure the response contains the expected "choices" field
|
||||
if (!isset($result['choices'][0]['message']['content'])) {
|
||||
throw new Exception('Unexpected response format from the DeepSeek API.');
|
||||
}
|
||||
|
||||
return $result['choices'][0]['message']['content'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a request to the DeepSeek API.
|
||||
*
|
||||
* @param string $url Endpoint to send the request to
|
||||
* @param string $method HTTP method (e.g., GET, POST)
|
||||
* @param array $data Data to send as JSON
|
||||
*
|
||||
* @throws Exception If a cURL error occurs
|
||||
*
|
||||
* @return string Raw response from the API
|
||||
*/
|
||||
private function sendRequest(string $url, string $method, array $data = []): string
|
||||
{
|
||||
$ch = curl_init($url);
|
||||
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, $this->headers);
|
||||
|
||||
$response = curl_exec($ch);
|
||||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
|
||||
if (curl_errno($ch)) {
|
||||
$errorMessage = curl_error($ch);
|
||||
curl_close($ch);
|
||||
throw new Exception("cURL Error: {$errorMessage}");
|
||||
}
|
||||
|
||||
curl_close($ch);
|
||||
|
||||
// Validate HTTP status codes
|
||||
if ($httpCode < 200 || $httpCode >= 300) {
|
||||
throw new Exception("Request to DeepSeek failed with HTTP status code: {$httpCode}");
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
17
plugin/ai_helper/src/deepseek/DeepSeekUrl.php
Normal file
17
plugin/ai_helper/src/deepseek/DeepSeekUrl.php
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
/* For license terms, see /license.txt */
|
||||
|
||||
class DeepSeekUrl
|
||||
{
|
||||
private const BASE_URL = 'https://api.deepseek.com/chat';
|
||||
|
||||
/**
|
||||
* Get the endpoint URL for chat completions.
|
||||
*
|
||||
* @return string URL for the chat completions endpoint
|
||||
*/
|
||||
public static function completionsUrl(): string
|
||||
{
|
||||
return self::BASE_URL.'/completions';
|
||||
}
|
||||
}
|
||||
341
plugin/ai_helper/src/openai/OpenAi.php
Normal file
341
plugin/ai_helper/src/openai/OpenAi.php
Normal file
@@ -0,0 +1,341 @@
|
||||
<?php
|
||||
/* For licensing terms, see /license.txt */
|
||||
|
||||
require_once 'OpenAiUrl.php';
|
||||
|
||||
class OpenAi
|
||||
{
|
||||
private $model = "gpt-4o"; // See https://platform.openai.com/docs/models for possible models
|
||||
private $headers;
|
||||
private $contentTypes;
|
||||
private $timeout = 0;
|
||||
private $streamMethod;
|
||||
|
||||
public function __construct(
|
||||
string $apiKey,
|
||||
string $organizationId = ''
|
||||
) {
|
||||
$this->contentTypes = [
|
||||
"application/json" => "Content-Type: application/json",
|
||||
"multipart/form-data" => "Content-Type: multipart/form-data",
|
||||
];
|
||||
|
||||
$this->headers = [
|
||||
$this->contentTypes["application/json"],
|
||||
"Authorization: Bearer $apiKey",
|
||||
];
|
||||
|
||||
if (!empty($organizationId)) {
|
||||
$this->headers[] = "OpenAI-Organization: $organizationId";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool|string
|
||||
*/
|
||||
public function listModels()
|
||||
{
|
||||
$url = OpenAiUrl::fineTuneModel();
|
||||
|
||||
return $this->sendRequest($url, 'GET');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $model
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
public function retrieveModel($model)
|
||||
{
|
||||
$model = "/$model";
|
||||
$url = OpenAiUrl::fineTuneModel().$model;
|
||||
|
||||
return $this->sendRequest($url, 'GET');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $opts
|
||||
* @param null $stream
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
public function completion(array $opts, callable $stream = null)
|
||||
{
|
||||
if ($stream !== null && isset($opts['stream']) && $opts['stream']) {
|
||||
$this->streamMethod = $stream;
|
||||
}
|
||||
|
||||
$opts['model'] = $opts['model'] ?? $this->model;
|
||||
$url = OpenAiUrl::completionsURL();
|
||||
|
||||
return $this->sendRequest($url, 'POST', $opts);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $opts
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
public function createEdit($opts)
|
||||
{
|
||||
$url = OpenAiUrl::editsUrl();
|
||||
|
||||
return $this->sendRequest($url, 'POST', $opts);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $opts
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
public function image($opts)
|
||||
{
|
||||
$url = OpenAiUrl::imageUrl()."/generations";
|
||||
|
||||
return $this->sendRequest($url, 'POST', $opts);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $opts
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
public function imageEdit($opts)
|
||||
{
|
||||
$url = OpenAiUrl::imageUrl()."/edits";
|
||||
|
||||
return $this->sendRequest($url, 'POST', $opts);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $opts
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
public function createImageVariation($opts)
|
||||
{
|
||||
$url = OpenAiUrl::imageUrl()."/variations";
|
||||
|
||||
return $this->sendRequest($url, 'POST', $opts);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $opts
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
public function moderation($opts)
|
||||
{
|
||||
$url = OpenAiUrl::moderationUrl();
|
||||
|
||||
return $this->sendRequest($url, 'POST', $opts);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $opts
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
public function uploadFile($opts)
|
||||
{
|
||||
$url = OpenAiUrl::filesUrl();
|
||||
|
||||
return $this->sendRequest($url, 'POST', $opts);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool|string
|
||||
*/
|
||||
public function listFiles()
|
||||
{
|
||||
$url = OpenAiUrl::filesUrl();
|
||||
|
||||
return $this->sendRequest($url, 'GET');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $fileId
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
public function retrieveFile($fileId)
|
||||
{
|
||||
$fileId = "/$fileId";
|
||||
$url = OpenAiUrl::filesUrl().$fileId;
|
||||
|
||||
return $this->sendRequest($url, 'GET');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $fileId
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
public function retrieveFileContent($fileId)
|
||||
{
|
||||
$fileId = "/$fileId/content";
|
||||
$url = OpenAiUrl::filesUrl().$fileId;
|
||||
|
||||
return $this->sendRequest($url, 'GET');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $fileId
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
public function deleteFile($fileId)
|
||||
{
|
||||
$fileId = "/$fileId";
|
||||
$url = OpenAiUrl::filesUrl().$fileId;
|
||||
|
||||
return $this->sendRequest($url, 'DELETE');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $opts
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
public function createFineTune($opts)
|
||||
{
|
||||
$url = OpenAiUrl::fineTuneUrl();
|
||||
|
||||
return $this->sendRequest($url, 'POST', $opts);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool|string
|
||||
*/
|
||||
public function listFineTunes()
|
||||
{
|
||||
$url = OpenAiUrl::fineTuneUrl();
|
||||
|
||||
return $this->sendRequest($url, 'GET');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $fineTuneId
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
public function retrieveFineTune($fineTuneId)
|
||||
{
|
||||
$fineTuneId = "/$fineTuneId";
|
||||
$url = OpenAiUrl::fineTuneUrl().$fineTuneId;
|
||||
|
||||
return $this->sendRequest($url, 'GET');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $fineTuneId
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
public function cancelFineTune($fineTuneId)
|
||||
{
|
||||
$fineTuneId = "/$fineTuneId/cancel";
|
||||
$url = OpenAiUrl::fineTuneUrl().$fineTuneId;
|
||||
|
||||
return $this->sendRequest($url, 'POST');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $fineTuneId
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
public function listFineTuneEvents($fineTuneId)
|
||||
{
|
||||
$fineTuneId = "/$fineTuneId/events";
|
||||
$url = OpenAiUrl::fineTuneUrl().$fineTuneId;
|
||||
|
||||
return $this->sendRequest($url, 'GET');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $fineTuneId
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
public function deleteFineTune($fineTuneId)
|
||||
{
|
||||
$fineTuneId = "/$fineTuneId";
|
||||
$url = OpenAiUrl::fineTuneModel().$fineTuneId;
|
||||
|
||||
return $this->sendRequest($url, 'DELETE');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $opts
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
public function embeddings($opts)
|
||||
{
|
||||
$url = OpenAiUrl::embeddings();
|
||||
|
||||
return $this->sendRequest($url, 'POST', $opts);
|
||||
}
|
||||
|
||||
public function setTimeout(int $timeout)
|
||||
{
|
||||
$this->timeout = $timeout;
|
||||
}
|
||||
|
||||
private function sendRequest(string $url, string $method, array $opts = []): string
|
||||
{
|
||||
$post_fields = json_encode($opts);
|
||||
|
||||
if (isset($opts['file']) || isset($opts['image'])) {
|
||||
$this->headers[0] = $this->contentTypes["multipart/form-data"];
|
||||
$post_fields = $opts;
|
||||
} else {
|
||||
$this->headers[0] = $this->contentTypes["application/json"];
|
||||
}
|
||||
$curl_info = [
|
||||
CURLOPT_URL => $url,
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_ENCODING => '',
|
||||
CURLOPT_MAXREDIRS => 10,
|
||||
CURLOPT_TIMEOUT => $this->timeout,
|
||||
CURLOPT_FOLLOWLOCATION => true,
|
||||
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
|
||||
CURLOPT_CUSTOMREQUEST => $method,
|
||||
CURLOPT_POSTFIELDS => $post_fields,
|
||||
CURLOPT_HTTPHEADER => $this->headers,
|
||||
];
|
||||
|
||||
if (empty($opts)) {
|
||||
unset($curl_info[CURLOPT_POSTFIELDS]);
|
||||
}
|
||||
|
||||
if (isset($opts['stream']) && $opts['stream']) {
|
||||
$curl_info[CURLOPT_WRITEFUNCTION] = $this->streamMethod;
|
||||
}
|
||||
|
||||
$curl = curl_init();
|
||||
|
||||
curl_setopt_array($curl, $curl_info);
|
||||
$response = curl_exec($curl);
|
||||
$httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
|
||||
|
||||
if (curl_errno($curl)) {
|
||||
$errorMessage = curl_error($curl);
|
||||
curl_close($curl);
|
||||
throw new Exception("cURL Error: {$errorMessage}");
|
||||
}
|
||||
|
||||
curl_close($curl);
|
||||
|
||||
if ($httpCode === 429) {
|
||||
throw new Exception("Insufficient quota. Please check your OpenAI account plan and billing details.");
|
||||
}
|
||||
|
||||
if ($httpCode < 200 || $httpCode >= 300) {
|
||||
throw new Exception("HTTP Error: {$httpCode}, Response: {$response}");
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
74
plugin/ai_helper/src/openai/OpenAiUrl.php
Normal file
74
plugin/ai_helper/src/openai/OpenAiUrl.php
Normal file
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
/* For licensing terms, see /license.txt */
|
||||
|
||||
class OpenAiUrl
|
||||
{
|
||||
public const ORIGIN = 'https://api.openai.com';
|
||||
public const API_VERSION = 'v1';
|
||||
public const OPEN_AI_URL = self::ORIGIN."/".self::API_VERSION;
|
||||
|
||||
public static function completionsURL(): string
|
||||
{
|
||||
return self::OPEN_AI_URL."/completions";
|
||||
}
|
||||
|
||||
public static function editsUrl(): string
|
||||
{
|
||||
return self::OPEN_AI_URL."/edits";
|
||||
}
|
||||
|
||||
public static function searchURL(string $engine): string
|
||||
{
|
||||
return self::OPEN_AI_URL."/engines/$engine/search";
|
||||
}
|
||||
|
||||
public static function enginesUrl(): string
|
||||
{
|
||||
return self::OPEN_AI_URL."/engines";
|
||||
}
|
||||
|
||||
public static function engineUrl(string $engine): string
|
||||
{
|
||||
return self::OPEN_AI_URL."/engines/$engine";
|
||||
}
|
||||
|
||||
public static function classificationsUrl(): string
|
||||
{
|
||||
return self::OPEN_AI_URL."/classifications";
|
||||
}
|
||||
|
||||
public static function moderationUrl(): string
|
||||
{
|
||||
return self::OPEN_AI_URL."/moderations";
|
||||
}
|
||||
|
||||
public static function filesUrl(): string
|
||||
{
|
||||
return self::OPEN_AI_URL."/files";
|
||||
}
|
||||
|
||||
public static function fineTuneUrl(): string
|
||||
{
|
||||
return self::OPEN_AI_URL."/fine-tunes";
|
||||
}
|
||||
|
||||
public static function fineTuneModel(): string
|
||||
{
|
||||
return self::OPEN_AI_URL."/models";
|
||||
}
|
||||
|
||||
public static function answersUrl(): string
|
||||
{
|
||||
return self::OPEN_AI_URL."/answers";
|
||||
}
|
||||
|
||||
public static function imageUrl(): string
|
||||
{
|
||||
return self::OPEN_AI_URL."/images";
|
||||
}
|
||||
|
||||
public static function embeddings(): string
|
||||
{
|
||||
return self::OPEN_AI_URL."/embeddings";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user