PluginProbe ʕ •ᴥ•ʔ
AI Engine – The Chatbot, AI Framework & MCP for WordPress / 1.0.8
AI Engine – The Chatbot, AI Framework & MCP for WordPress v1.0.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
286 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 uploadFile( $filename, $data )
94 {
95 $result = $this->run('POST', '/files', null, ['data' => $data, 'filename' => $filename]);
96 return $result;
97 }
98
99 public function deleteFile( $fileId )
100 {
101 return $this->run('DELETE', '/files/' . $fileId);
102 }
103
104 public function getModel( $modelId )
105 {
106 return $this->run('GET', '/models/' . $modelId);
107 }
108
109 public function deleteFineTune( $modelId )
110 {
111 return $this->run('DELETE', '/models/' . $modelId);
112 }
113
114 public function downloadFile( $fileId )
115 {
116 return $this->run('GET', '/files/' . $fileId . '/content', null, null, false);
117 }
118
119 public function fineTuneFile( $fileId, $model, $suffix, $hyperparams = [] )
120 {
121 $n_epochs = isset( $hyperparams['nEpochs'] ) ? (int)$hyperparams['nEpochs'] : 4;
122 $batch_size = isset( $hyperparams['batchSize'] ) ? (int)$hyperparams['batchSize'] : null;
123 $arguments = [
124 'training_file' => $fileId,
125 'model' => $model,
126 'suffix' => $suffix,
127 'n_epochs' => $n_epochs
128 ];
129 if ( $batch_size ) {
130 $arguments['batch_size'] = $batch_size;
131 }
132 $result = $this->run('POST', '/fine-tunes', $arguments);
133 return $result;
134 }
135
136 public function create_body_for_file($file, $boundary)
137 {
138 $fields = array(
139 'purpose' => 'fine-tune',
140 'file' => $file['filename']
141 );
142
143 $body = '';
144 foreach ($fields as $name => $value) {
145 $body .= "--$boundary\r\n";
146 $body .= "Content-Disposition: form-data; name=\"$name\"";
147 if ($name == 'file') {
148 $body .= "; filename=\"{$value}\"\r\n";
149 $body .= "Content-Type: application/json\r\n\r\n";
150 $body .= $file['data'] . "\r\n";
151 } else {
152 $body .= "\r\n\r\n$value\r\n";
153 }
154 }
155 $body .= "--$boundary--\r\n";
156 return $body;
157 }
158
159 public function run($method, $url, $query = null, $file = null, $json = true)
160 {
161 $apiKey = $this->apiKey;
162 $headers = "Content-Type: application/json\r\n" . "Authorization: Bearer " . $apiKey . "\r\n";
163 $body = $query ? json_encode($query) : null;
164 if (!empty($file)) {
165 $boundary = wp_generate_password(24, false);
166 $headers = [
167 'Content-Type' => 'multipart/form-data; boundary=' . $boundary,
168 'Authorization' => 'Bearer ' . $this->apiKey,
169 ];
170 $body = $this->create_body_for_file($file, $boundary);
171 }
172
173 $url = 'https://api.openai.com/v1' . $url;
174 $options = [
175 "headers" => $headers,
176 "method" => $method,
177 "timeout" => 120,
178 "body" => $body,
179 "sslverify" => false
180 ];
181
182 try {
183 $response = wp_remote_request($url, $options);
184 if (is_wp_error($response)) {
185 throw new Exception($response->get_error_message());
186 }
187 $response = wp_remote_retrieve_body($response);
188 $data = $json ? json_decode($response, true) : $response;
189
190 // Error handling
191 if (isset($data['error'])) {
192 $message = $data['error']['message'];
193 // If the message contains "Incorrect API key provided: THE_KEY.", replace the key by "----".
194 if (preg_match('/API key provided(: .*)\./', $message, $matches)) {
195 $message = str_replace($matches[1], '', $message);
196 }
197 throw new Exception($message);
198 }
199
200 return $data;
201 }
202 catch (Exception $e) {
203 error_log($e->getMessage());
204 throw new Exception('Error while calling OpenAI: ' . $e->getMessage());
205 }
206 }
207
208 private function calculatePrice( $model, $units, $option = null )
209 {
210 foreach ( MWAI_OPENAI_PRICING as $price ) {
211 if ( $price['model'] == $model ) {
212 if ( $price['type'] == 'image' ) {
213 if ( !$option ) {
214 error_log( "AI Engine: Image models require an option." );
215 return null;
216 }
217 else {
218 foreach ( $price['options'] as $imageType ) {
219 if ( $imageType['option'] == $option ) {
220 return $imageType['price'] * $units;
221 }
222 }
223 }
224 }
225 else {
226 return $price['price'] * $price['unit'] * $units;
227 }
228 }
229 }
230 error_log( "AI Engine: Invalid model ($model)." );
231 return null;
232 }
233
234 public function getPrice( Meow_MWAI_Query $query, Meow_MWAI_Answer $answer )
235 {
236 $model = $query->model;
237 $modelBase = null;
238 $units = 0;
239 $option = null;
240 if ( is_a( $query, 'Meow_MWAI_QueryText' ) ) {
241 // Finetuned models
242 if ( preg_match('/^([a-zA-Z]{0,32}):/', $model, $matches ) ) {
243 $modelBase = "fn-" . $matches[1];
244 }
245 // Standard models
246 else if ( preg_match('/^text-(\w+)-\d+/', $model, $matches ) ) {
247 $modelBase = $matches[1];
248 }
249 if ( empty( $modelBase ) ) {
250 error_log("AI Engine: Cannot find the base model for $model.");
251 return null;
252 }
253 $units = $answer->getTotalTokens();
254 }
255 else if ( is_a( $query, 'Meow_MWAI_QueryImage' ) ) {
256 $modelBase = 'dall-e';
257 $units = $query->maxResults;
258 $option = "1024x1024";
259 }
260 return $this->calculatePrice( $modelBase, $units, $option );
261 }
262
263 public function getIncidents() {
264 $url = 'https://status.openai.com/history.rss';
265 $response = wp_remote_get( $url );
266 if ( is_wp_error( $response ) ) {
267 throw new Exception( $response->get_error_message() );
268 }
269 $response = wp_remote_retrieve_body( $response );
270 $xml = simplexml_load_string( $response );
271 $incidents = array();
272 $oneWeekAgo = time() - 7 * 24 * 60 * 60;
273 foreach ( $xml->channel->item as $item ) {
274 $date = strtotime( $item->pubDate );
275 if ( $date > $oneWeekAgo ) {
276 $incidents[] = array(
277 'title' => (string) $item->title,
278 'description' => (string) $item->description,
279 'date' => $date
280 );
281 }
282 }
283 return $incidents;
284 }
285 }
286