PluginProbe ʕ •ᴥ•ʔ
AI Engine – The Chatbot, AI Framework & MCP for WordPress / 1.2.1
AI Engine – The Chatbot, AI Framework & MCP for WordPress v1.2.1
3.5.7 3.5.6 3.5.5 3.5.4 3.5.3 3.5.2 3.5.1 3.5.0 3.4.9 3.4.8 3.4.7 0.2.1 1.6.91 0.2.2 1.6.92 0.2.3 1.6.93 0.2.4 1.6.94 0.2.5 1.6.95 0.2.6 1.6.96 0.2.7 1.6.97 0.2.8 1.6.98 0.2.9 1.6.99 0.3.0 1.7.0 0.3.1 1.7.1 0.3.2 1.7.2 0.3.3 1.7.3 0.3.4 1.7.4 0.3.5 1.7.5 0.3.6 1.7.6 0.4.0 1.7.7 0.4.1 1.7.8 0.4.2 1.7.9 0.4.3 1.8.0 0.4.4 1.8.1 0.4.5 1.8.2 0.4.6 1.8.3 0.4.7 1.8.4 0.4.8 1.8.5 0.4.9 1.8.6 0.5.0 1.8.7 0.5.1 1.8.8 0.5.2 1.8.9 0.5.3 1.9.0 0.5.4 1.9.1 0.5.5 1.9.2 0.5.6 1.9.3 0.5.7 1.9.4 0.5.8 1.9.5 0.5.9 1.9.6 0.6.0 1.9.7 0.6.1 1.9.8 0.6.2 1.9.81 0.6.3 1.9.82 0.6.4 1.9.83 0.6.5 1.9.84 0.6.6 1.9.85 0.6.7 1.9.86 0.6.8 1.9.87 0.6.9 1.9.88 0.7.0 1.9.89 0.7.1 1.9.90 0.7.2 1.9.91 0.7.3 1.9.92 0.7.4 1.9.93 0.7.5 1.9.94 0.7.6 1.9.95 0.7.7 1.9.96 0.7.8 1.9.97 0.7.9 1.9.98 0.8.0 1.9.99 0.8.1 2.0.0 0.8.2 2.0.1 0.8.3 2.0.2 0.8.4 2.0.3 0.8.5 2.0.4 0.8.6 2.0.5 0.8.7 2.0.6 0.8.8 2.0.7 0.8.9 2.0.8 0.9.0 2.0.9 0.9.2 2.1.0 0.9.3 2.1.1 0.9.4 2.1.2 0.9.5 2.1.3 0.9.6 2.1.4 0.9.7 2.1.5 0.9.8 2.1.6 0.9.81 2.1.7 0.9.82 2.1.8 0.9.83 2.1.9 0.9.84 2.2.0 0.9.85 2.2.1 0.9.86 2.2.2 0.9.87 2.2.3 0.9.88 2.2.4 0.9.89 2.2.5 0.9.9 2.2.51 0.9.91 2.2.52 0.9.92 2.2.53 0.9.93 2.2.54 0.9.94 2.2.56 0.9.95 2.2.57 0.9.96 2.2.6 0.9.97 2.2.60 0.9.98 2.2.61 0.9.99 2.2.62 1.0.0 2.2.63 1.0.01 2.2.70 1.0.1 2.2.80 1.0.2 2.2.81 1.0.3 2.2.90 1.0.4 2.2.91 1.0.5 2.2.92 1.0.6 2.2.93 1.0.7 2.2.94 1.0.8 2.2.95 1.0.9 2.3.0 1.1.0 2.3.1 1.1.1 2.3.2 1.1.2 2.3.3 1.1.3 2.3.4 1.1.4 2.3.5 1.1.5 2.3.6 1.1.6 2.3.7 1.1.7 2.3.8 1.1.8 2.3.9 1.1.9 2.4.0 1.2.0 2.4.1 1.2.1 2.4.2 1.2.2 2.4.3 1.2.21 2.4.4 1.2.3 2.4.5 1.2.30 2.4.6 1.3.0 2.4.7 1.3.1 2.4.8 1.3.2 2.4.9 1.3.3 2.5.0 1.3.31 2.5.1 1.3.32 2.5.2 1.3.33 2.5.3 1.3.34 2.5.4 1.3.35 2.5.5 1.3.36 2.5.6 1.3.37 2.5.7 1.3.38 2.5.8 1.3.39 2.5.9 1.3.40 2.6.0 1.3.41 2.6.1 1.3.42 2.6.2 1.3.43 2.6.3 1.3.44 2.6.5 1.3.45 2.6.6 1.3.46 2.6.7 1.3.47 2.6.8 1.3.48 2.6.9 1.3.49 2.7.0 1.3.50 2.7.1 1.3.51 2.7.2 1.3.52 2.7.3 1.3.53 2.7.4 1.3.54 2.7.5 1.3.56 2.7.6 1.3.57 2.7.7 1.3.58 2.7.8 1.3.59 2.7.9 1.3.60 2.8.0 1.3.61 2.8.1 1.3.62 2.8.2 1.3.63 2.8.3 1.3.64 2.8.4 1.3.65 2.8.5 1.3.66 2.8.6 1.3.67 2.8.7 1.3.68 2.8.8 1.3.69 2.8.9 1.3.70 2.9.0 1.3.71 2.9.1 1.3.72 2.9.2 1.3.73 2.9.3 1.3.74 2.9.4 1.3.75 2.9.5 1.3.76 2.9.6 1.3.77 2.9.7 1.3.78 2.9.8 1.3.79 2.9.9 1.3.80 3.0.0 1.3.81 3.0.1 1.3.82 3.0.2 1.3.83 3.0.3 1.3.84 3.0.4 1.3.85 3.0.5 1.3.86 3.0.6 1.3.87 3.0.7 1.3.88 3.0.8 1.3.89 3.0.9 1.3.90 3.1.0 1.3.91 3.1.1 1.3.92 3.1.2 1.3.93 3.1.3 1.3.94 3.1.4 1.3.95 3.1.5 1.3.96 3.1.6 1.3.97 3.1.7 1.3.98 3.1.8 1.3.99 3.1.9 1.4.0 3.2.0 1.4.1 3.2.1 1.4.2 3.2.2 1.4.3 3.2.3 1.4.4 3.2.4 1.4.5 3.2.5 1.4.6 3.2.6 1.4.7 3.2.7 1.4.8 3.2.8 1.4.9 3.2.9 1.5.0 3.3.0 1.5.1 3.3.1 1.5.2 3.3.2 1.5.3 3.3.3 1.5.4 3.3.4 1.5.5 3.3.5 1.5.6 3.3.6 1.5.7 3.3.7 1.5.8 3.3.8 1.5.9 3.3.9 1.6.0 3.4.0 1.6.1 3.4.1 1.6.2 3.4.2 1.6.3 3.4.3 1.6.5 3.4.4 1.6.51 3.4.5 1.6.52 3.4.6 1.6.53 1.6.54 1.6.55 1.6.56 1.6.57 1.6.58 1.6.59 1.6.60 1.6.61 1.6.62 1.6.63 1.6.64 1.6.65 1.6.66 1.6.67 1.6.68 trunk 1.6.69 0.0.1 1.6.70 0.0.2 1.6.71 0.0.3 1.6.72 0.0.4 1.6.73 0.0.5 1.6.74 0.0.6 1.6.75 0.0.7 1.6.76 0.0.8 1.6.77 0.0.9 1.6.78 0.1.0 1.6.79 0.1.1 1.6.81 0.1.2 1.6.82 0.1.3 1.6.83 0.1.4 1.6.84 0.1.5 1.6.85 0.1.6 1.6.86 0.1.7 1.6.87 0.1.8 1.6.88 0.1.9 1.6.89 0.2.0 1.6.90
ai-engine / classes / openai.php
ai-engine / classes Last commit date
modules 3 years ago admin.php 3 years ago ai.php 3 years ago answer.php 3 years ago core.php 3 years ago init.php 3 years ago openai.php 3 years ago query.php 3 years ago queryembed.php 3 years ago queryimage.php 3 years ago querytext.php 3 years ago rest.php 3 years ago ui.php 3 years ago
openai.php
318 lines
1 <?php
2
3 class Meow_MWAI_OpenAI
4 {
5 private $core = null;
6 private $apiKey = null;
7
8 public function __construct($core)
9 {
10 $this->core = $core;
11 $this->apiKey = $this->core->get_option( 'openai_apikey' );
12 }
13
14 public function listFiles()
15 {
16 return $this->run( 'GET', '/files' );
17 }
18
19 function getSuffixForModel($model)
20 {
21 preg_match("/:([a-zA-Z\-]{1,40})-([0-9]{4})-([0-9]{2})-([0-9]{2})/", $model, $matches);
22 if ( count( $matches ) > 0 ) {
23 return $matches[1];
24 }
25 return 'N/A';
26 }
27
28 function getBaseModel($model)
29 {
30 preg_match("/:([a-zA-Z\-]{1,40})-([0-9]{4})-([0-9]{2})-([0-9]{2})/", $model, $matches);
31 if (count($matches) > 0) {
32 return $matches[1];
33 }
34 return 'N/A';
35 }
36
37 public function listFineTunes( $clean = false )
38 {
39 $finetunes = $this->run('GET', '/fine-tunes');
40
41 if ( $clean ) {
42 $deleted = [];
43 $finetunes['data'] = array_filter( $finetunes['data'], function ( $finetune ) use ( &$deleted ) {
44 $name = $finetune['fine_tuned_model'];
45 $isSucceeded = $finetune['status'] === 'succeeded';
46 $exist = true;
47 if ($isSucceeded) {
48 try {
49 $finetune = $this->getModel( $name );
50 }
51 catch ( Exception $e ) {
52 $exist = false;
53 $deleted[] = $name;
54 }
55 }
56 return $exist;
57 });
58 $this->core->update_option( 'openai_finetunes_deleted', $deleted );
59 }
60
61 $finetunes['data'] = array_map( function ( $finetune ) {
62 $finetune['suffix'] = $this->getSuffixForModel( $finetune['fine_tuned_model'] );
63 return $finetune;
64 }, $finetunes['data']);
65
66 // Get option openai_finetunes_deleted
67 $deleted_finetunes = $this->core->get_option('openai_finetunes_deleted');
68
69 // Remove all deleted finetunes from the list, make a new array, without using array_filter
70 $finetunes['data'] = array_values(array_filter($finetunes['data'], function ($finetune) use ($deleted_finetunes) {
71 return !in_array($finetune['fine_tuned_model'], $deleted_finetunes);
72 }));
73
74 $finetunes_option = $this->core->get_option('openai_finetunes');
75 $fresh_finetunes_options = array_map(function ($finetune) use ($finetunes_option) {
76 $entry = [];
77 $model = $finetune['fine_tuned_model'];
78 $entry['suffix'] = $finetune['suffix'];
79 $entry['model'] = $model;
80 $entry['enabled'] = true;
81 for ($i = 0; $i < count($finetunes_option); $i++) {
82 if ($finetunes_option[$i]['model'] === $model) {
83 $entry['enabled'] = $finetunes_option[$i]['enabled'];
84 break;
85 }
86 }
87 return $entry;
88 }, $finetunes['data']);
89 $this->core->update_option('openai_finetunes', $fresh_finetunes_options);
90 return $finetunes;
91 }
92
93 public function moderate( $input ) {
94 $result = $this->run('POST', '/moderations', [
95 'input' => $input
96 ]);
97 return $result;
98 }
99
100 public function uploadFile( $filename, $data )
101 {
102 $result = $this->run('POST', '/files', null, ['data' => $data, 'filename' => $filename]);
103 return $result;
104 }
105
106 public function deleteFile( $fileId )
107 {
108 return $this->run('DELETE', '/files/' . $fileId);
109 }
110
111 public function getModel( $modelId )
112 {
113 return $this->run('GET', '/models/' . $modelId);
114 }
115
116 public function deleteFineTune( $modelId )
117 {
118 return $this->run('DELETE', '/models/' . $modelId);
119 }
120
121 public function downloadFile( $fileId )
122 {
123 return $this->run('GET', '/files/' . $fileId . '/content', null, null, false);
124 }
125
126 public function fineTuneFile( $fileId, $model, $suffix, $hyperparams = [] )
127 {
128 $n_epochs = isset( $hyperparams['nEpochs'] ) ? (int)$hyperparams['nEpochs'] : 4;
129 $batch_size = isset( $hyperparams['batchSize'] ) ? (int)$hyperparams['batchSize'] : null;
130 $arguments = [
131 'training_file' => $fileId,
132 'model' => $model,
133 'suffix' => $suffix,
134 'n_epochs' => $n_epochs
135 ];
136 if ( $batch_size ) {
137 $arguments['batch_size'] = $batch_size;
138 }
139 $result = $this->run('POST', '/fine-tunes', $arguments);
140 return $result;
141 }
142
143 public function create_body_for_file($file, $boundary)
144 {
145 $fields = array(
146 'purpose' => 'fine-tune',
147 'file' => $file['filename']
148 );
149
150 $body = '';
151 foreach ($fields as $name => $value) {
152 $body .= "--$boundary\r\n";
153 $body .= "Content-Disposition: form-data; name=\"$name\"";
154 if ($name == 'file') {
155 $body .= "; filename=\"{$value}\"\r\n";
156 $body .= "Content-Type: application/json\r\n\r\n";
157 $body .= $file['data'] . "\r\n";
158 } else {
159 $body .= "\r\n\r\n$value\r\n";
160 }
161 }
162 $body .= "--$boundary--\r\n";
163 return $body;
164 }
165
166 public function run( $method, $url, $query = null, $file = null, $json = true )
167 {
168 $apiKey = $this->apiKey;
169 $headers = "Content-Type: application/json\r\n" . "Authorization: Bearer " . $apiKey . "\r\n";
170 $body = $query ? json_encode( $query ) : null;
171 if ( !empty( $file ) ) {
172 $boundary = wp_generate_password (24, false );
173 $headers = [
174 'Content-Type' => 'multipart/form-data; boundary=' . $boundary,
175 'Authorization' => 'Bearer ' . $this->apiKey,
176 ];
177 $body = $this->create_body_for_file( $file, $boundary );
178 }
179
180 $url = 'https://api.openai.com/v1' . $url;
181 $options = [
182 "headers" => $headers,
183 "method" => $method,
184 "timeout" => 120,
185 "body" => $body,
186 "sslverify" => false
187 ];
188
189 try {
190 $response = wp_remote_request( $url, $options );
191 if ( is_wp_error( $response ) ) {
192 throw new Exception( $response->get_error_message() );
193 }
194 $response = wp_remote_retrieve_body( $response );
195 $data = $json ? json_decode( $response, true ) : $response;
196
197 // Error handling
198 if ( isset( $data['error'] ) ) {
199 $message = $data['error']['message'];
200 // If the message contains "Incorrect API key provided: THE_KEY.", replace the key by "----".
201 if ( preg_match( '/API key provided(: .*)\./', $message, $matches ) ) {
202 $message = str_replace( $matches[1], '', $message );
203 }
204 throw new Exception( $message );
205 }
206
207 return $data;
208 }
209 catch ( Exception $e ) {
210 error_log( $e->getMessage() );
211 throw new Exception( 'Error while calling OpenAI: ' . $e->getMessage() );
212 }
213 }
214
215 private function calculatePrice( $modelFamily, $units, $option = null, $finetune = false )
216 {
217 foreach ( MWAI_OPENAI_MODELS as $currentModel ) {
218 if ( $currentModel['family'] === $modelFamily ) {
219 if ( $currentModel['type'] === 'image' ) {
220 if ( !$option ) {
221 error_log( "AI Engine: Image models require an option." );
222 return null;
223 }
224 else {
225 foreach ( $currentModel['options'] as $imageType ) {
226 if ( $imageType['option'] == $option ) {
227 return $imageType['price'] * $units;
228 }
229 }
230 }
231 }
232 else {
233 if ( $finetune ) {
234 // Why * 2? Need to check why I did this.
235 return $currentModel['finetune']['price'] * $currentModel['unit'] * $units * 2;
236 }
237 return $currentModel['price'] * $currentModel['unit'] * $units;
238 }
239 }
240 }
241 error_log( "AI Engine: Invalid family ($modelFamily)." );
242 return null;
243 }
244
245 public function getPrice( Meow_MWAI_Query $query, Meow_MWAI_Answer $answer )
246 {
247 $model = $query->model;
248 $family = null;
249 $units = 0;
250 $option = null;
251
252 $finetune = false;
253 if ( is_a( $query, 'Meow_MWAI_QueryText' ) ) {
254 // Finetuned models
255 if ( preg_match('/^([a-zA-Z]{0,32}):/', $model, $matches ) ) {
256 $family = $matches[1];
257 $finetune = true;
258 }
259 // Standard models
260 else {
261 foreach ( MWAI_OPENAI_MODELS as $currentModel ) {
262 if ( $currentModel['model'] == $model ) {
263 $family = $currentModel['family'];
264 break;
265 }
266 }
267 }
268 if ( empty( $family ) ) {
269 error_log("AI Engine: Cannot find the base model for $model.");
270 return null;
271 }
272 $units = $answer->getTotalTokens();
273 }
274 else if ( is_a( $query, 'Meow_MWAI_QueryImage' ) ) {
275 $family = 'dall-e';
276 $units = $query->maxResults;
277 $option = "1024x1024";
278 }
279 else if ( is_a( $query, 'Meow_MWAI_QueryEmbed' ) ) {
280 foreach ( MWAI_OPENAI_MODELS as $currentModel ) {
281 if ( $currentModel['model'] == $model ) {
282 $family = $currentModel['family'];
283 break;
284 }
285 }
286 $units = $answer->getTotalTokens();
287 }
288 else {
289 error_log("AI Engine: Cannot find the base model for $model.");
290 return null;
291 }
292 return $this->calculatePrice( $family, $units, $option, $finetune );
293 }
294
295 public function getIncidents() {
296 $url = 'https://status.openai.com/history.rss';
297 $response = wp_remote_get( $url );
298 if ( is_wp_error( $response ) ) {
299 throw new Exception( $response->get_error_message() );
300 }
301 $response = wp_remote_retrieve_body( $response );
302 $xml = simplexml_load_string( $response );
303 $incidents = array();
304 $oneWeekAgo = time() - 7 * 24 * 60 * 60;
305 foreach ( $xml->channel->item as $item ) {
306 $date = strtotime( $item->pubDate );
307 if ( $date > $oneWeekAgo ) {
308 $incidents[] = array(
309 'title' => (string) $item->title,
310 'description' => (string) $item->description,
311 'date' => $date
312 );
313 }
314 }
315 return $incidents;
316 }
317 }
318