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