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