PluginProbe ʕ •ᴥ•ʔ
AI Engine – The Chatbot, AI Framework & MCP for WordPress / 1.1.8
AI Engine – The Chatbot, AI Framework & MCP for WordPress v1.1.8
3.5.9 3.5.8 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 queryimage.php 3 years ago querytext.php 3 years ago rest.php 3 years ago ui.php 3 years ago
openai.php
313 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 createEmbedding( $input, $model = "text-embedding-ada-002" ) {
38 $data = array(
39 'input' => $input,
40 'model' => $model
41 );
42 return $this->run( 'POST', '/embeddings', $data );
43 }
44
45 public function listFineTunes( $clean = false )
46 {
47 $finetunes = $this->run('GET', '/fine-tunes');
48
49 if ( $clean ) {
50 $deleted = [];
51 $finetunes['data'] = array_filter( $finetunes['data'], function ( $finetune ) use ( &$deleted ) {
52 $name = $finetune['fine_tuned_model'];
53 $isSucceeded = $finetune['status'] === 'succeeded';
54 $exist = true;
55 if ($isSucceeded) {
56 try {
57 $finetune = $this->getModel( $name );
58 }
59 catch ( Exception $e ) {
60 $exist = false;
61 $deleted[] = $name;
62 }
63 }
64 return $exist;
65 });
66 $this->core->update_option( 'openai_finetunes_deleted', $deleted );
67 }
68
69 $finetunes['data'] = array_map( function ( $finetune ) {
70 $finetune['suffix'] = $this->getSuffixForModel( $finetune['fine_tuned_model'] );
71 return $finetune;
72 }, $finetunes['data']);
73
74 // Get option openai_finetunes_deleted
75 $deleted_finetunes = $this->core->get_option('openai_finetunes_deleted');
76
77 // Remove all deleted finetunes from the list, make a new array, without using array_filter
78 $finetunes['data'] = array_values(array_filter($finetunes['data'], function ($finetune) use ($deleted_finetunes) {
79 return !in_array($finetune['fine_tuned_model'], $deleted_finetunes);
80 }));
81
82 $finetunes_option = $this->core->get_option('openai_finetunes');
83 $fresh_finetunes_options = array_map(function ($finetune) use ($finetunes_option) {
84 $entry = [];
85 $model = $finetune['fine_tuned_model'];
86 $entry['suffix'] = $finetune['suffix'];
87 $entry['model'] = $model;
88 $entry['enabled'] = true;
89 for ($i = 0; $i < count($finetunes_option); $i++) {
90 if ($finetunes_option[$i]['model'] === $model) {
91 $entry['enabled'] = $finetunes_option[$i]['enabled'];
92 break;
93 }
94 }
95 return $entry;
96 }, $finetunes['data']);
97 $this->core->update_option('openai_finetunes', $fresh_finetunes_options);
98 return $finetunes;
99 }
100
101 public function moderate( $input ) {
102 $result = $this->run('POST', '/moderations', [
103 'input' => $input
104 ]);
105 return $result;
106 }
107
108 public function uploadFile( $filename, $data )
109 {
110 $result = $this->run('POST', '/files', null, ['data' => $data, 'filename' => $filename]);
111 return $result;
112 }
113
114 public function deleteFile( $fileId )
115 {
116 return $this->run('DELETE', '/files/' . $fileId);
117 }
118
119 public function getModel( $modelId )
120 {
121 return $this->run('GET', '/models/' . $modelId);
122 }
123
124 public function deleteFineTune( $modelId )
125 {
126 return $this->run('DELETE', '/models/' . $modelId);
127 }
128
129 public function downloadFile( $fileId )
130 {
131 return $this->run('GET', '/files/' . $fileId . '/content', null, null, false);
132 }
133
134 public function fineTuneFile( $fileId, $model, $suffix, $hyperparams = [] )
135 {
136 $n_epochs = isset( $hyperparams['nEpochs'] ) ? (int)$hyperparams['nEpochs'] : 4;
137 $batch_size = isset( $hyperparams['batchSize'] ) ? (int)$hyperparams['batchSize'] : null;
138 $arguments = [
139 'training_file' => $fileId,
140 'model' => $model,
141 'suffix' => $suffix,
142 'n_epochs' => $n_epochs
143 ];
144 if ( $batch_size ) {
145 $arguments['batch_size'] = $batch_size;
146 }
147 $result = $this->run('POST', '/fine-tunes', $arguments);
148 return $result;
149 }
150
151 public function create_body_for_file($file, $boundary)
152 {
153 $fields = array(
154 'purpose' => 'fine-tune',
155 'file' => $file['filename']
156 );
157
158 $body = '';
159 foreach ($fields as $name => $value) {
160 $body .= "--$boundary\r\n";
161 $body .= "Content-Disposition: form-data; name=\"$name\"";
162 if ($name == 'file') {
163 $body .= "; filename=\"{$value}\"\r\n";
164 $body .= "Content-Type: application/json\r\n\r\n";
165 $body .= $file['data'] . "\r\n";
166 } else {
167 $body .= "\r\n\r\n$value\r\n";
168 }
169 }
170 $body .= "--$boundary--\r\n";
171 return $body;
172 }
173
174 public function run( $method, $url, $query = null, $file = null, $json = true )
175 {
176 $apiKey = $this->apiKey;
177 $headers = "Content-Type: application/json\r\n" . "Authorization: Bearer " . $apiKey . "\r\n";
178 $body = $query ? json_encode( $query ) : null;
179 if ( !empty( $file ) ) {
180 $boundary = wp_generate_password (24, false );
181 $headers = [
182 'Content-Type' => 'multipart/form-data; boundary=' . $boundary,
183 'Authorization' => 'Bearer ' . $this->apiKey,
184 ];
185 $body = $this->create_body_for_file( $file, $boundary );
186 }
187
188 $url = 'https://api.openai.com/v1' . $url;
189 $options = [
190 "headers" => $headers,
191 "method" => $method,
192 "timeout" => 120,
193 "body" => $body,
194 "sslverify" => false
195 ];
196
197 try {
198 $response = wp_remote_request( $url, $options );
199 if ( is_wp_error( $response ) ) {
200 throw new Exception( $response->get_error_message() );
201 }
202 $response = wp_remote_retrieve_body( $response );
203 $data = $json ? json_decode( $response, true ) : $response;
204
205 // Error handling
206 if ( isset( $data['error'] ) ) {
207 $message = $data['error']['message'];
208 // If the message contains "Incorrect API key provided: THE_KEY.", replace the key by "----".
209 if ( preg_match( '/API key provided(: .*)\./', $message, $matches ) ) {
210 $message = str_replace( $matches[1], '', $message );
211 }
212 throw new Exception( $message );
213 }
214
215 return $data;
216 }
217 catch ( Exception $e ) {
218 error_log( $e->getMessage() );
219 throw new Exception( 'Error while calling OpenAI: ' . $e->getMessage() );
220 }
221 }
222
223 private function calculatePrice( $modelFamily, $units, $option = null, $finetune = false )
224 {
225 foreach ( MWAI_OPENAI_MODELS as $currentModel ) {
226 if ( $currentModel['family'] === $modelFamily ) {
227 if ( $currentModel['type'] === 'image' ) {
228 if ( !$option ) {
229 error_log( "AI Engine: Image models require an option." );
230 return null;
231 }
232 else {
233 foreach ( $currentModel['options'] as $imageType ) {
234 if ( $imageType['option'] == $option ) {
235 return $imageType['price'] * $units;
236 }
237 }
238 }
239 }
240 else {
241 if ( $finetune ) {
242 // Why * 2? Need to check why I did this.
243 return $currentModel['finetune']['price'] * $currentModel['unit'] * $units * 2;
244 }
245 return $currentModel['price'] * $currentModel['unit'] * $units;
246 }
247 }
248 }
249 error_log( "AI Engine: Invalid family ($modelFamily)." );
250 return null;
251 }
252
253 public function getPrice( Meow_MWAI_Query $query, Meow_MWAI_Answer $answer )
254 {
255 $model = $query->model;
256 $family = null;
257 $units = 0;
258 $option = null;
259
260 $finetune = false;
261 if ( is_a( $query, 'Meow_MWAI_QueryText' ) ) {
262 // Finetuned models
263 if ( preg_match('/^([a-zA-Z]{0,32}):/', $model, $matches ) ) {
264 $family = $matches[1];
265 $finetune = true;
266 }
267 // Standard models
268 else {
269 foreach ( MWAI_OPENAI_MODELS as $currentModel ) {
270 if ( $currentModel['model'] == $model ) {
271 $family = $currentModel['family'];
272 break;
273 }
274 }
275 }
276 if ( empty( $family ) ) {
277 error_log("AI Engine: Cannot find the base model for $model.");
278 return null;
279 }
280 $units = $answer->getTotalTokens();
281 }
282 else if ( is_a( $query, 'Meow_MWAI_QueryImage' ) ) {
283 $family = 'dall-e';
284 $units = $query->maxResults;
285 $option = "1024x1024";
286 }
287 return $this->calculatePrice( $family, $units, $option, $finetune );
288 }
289
290 public function getIncidents() {
291 $url = 'https://status.openai.com/history.rss';
292 $response = wp_remote_get( $url );
293 if ( is_wp_error( $response ) ) {
294 throw new Exception( $response->get_error_message() );
295 }
296 $response = wp_remote_retrieve_body( $response );
297 $xml = simplexml_load_string( $response );
298 $incidents = array();
299 $oneWeekAgo = time() - 7 * 24 * 60 * 60;
300 foreach ( $xml->channel->item as $item ) {
301 $date = strtotime( $item->pubDate );
302 if ( $date > $oneWeekAgo ) {
303 $incidents[] = array(
304 'title' => (string) $item->title,
305 'description' => (string) $item->description,
306 'date' => $date
307 );
308 }
309 }
310 return $incidents;
311 }
312 }
313