PluginProbe ʕ •ᴥ•ʔ
AI Engine – The Chatbot, AI Framework & MCP for WordPress / 1.6.87
AI Engine – The Chatbot, AI Framework & MCP for WordPress v1.6.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 / engines / core.php
ai-engine / classes / engines Last commit date
core.php 3 years ago openai.php 3 years ago
core.php
325 lines
1 <?php
2
3 class Meow_MWAI_Engines_Core {
4 private $core = null;
5 private $openai = null;
6 private $localApiKey = null;
7 private $localService = null;
8 private $localAzureEndpoint = null;
9 private $localAzureApiKey = null;
10 private $localAzureDeployments = null;
11 private $openaiEndpoint = 'https://api.openai.com/v1';
12 private $azureApiVersion = '?api-version=2023-03-15-preview';
13
14 public function __construct( $core ) {
15 $this->core = $core;
16 $this->openai = new Meow_MWAI_Engines_OpenAI( $this->core );
17 $this->localService = $this->core->get_option( 'openai_service' );
18 $this->localApiKey = $this->core->get_option( 'openai_apikey' );
19 $this->localAzureEndpoint = $this->core->get_option( 'openai_azure_endpoint' );
20 $this->localAzureApiKey = $this->core->get_option( 'openai_azure_apikey' );
21 $this->localAzureDeployments = $this->core->get_option( 'openai_azure_deployments' );
22 }
23
24 private function buildHeaders( $query ) {
25 $headers = array(
26 'Content-Type' => 'application/json',
27 'Authorization' => 'Bearer ' . $query->apiKey,
28 );
29 if ( $query->service === 'azure' ) {
30 $headers = array( 'Content-Type' => 'application/json', 'api-key' => $query->azureApiKey );
31 }
32 return $headers;
33 }
34
35 private function buildOptions( $headers, $json = null, $forms = null ) {
36
37 // Build body
38 $body = null;
39 if ( !empty( $forms ) ) {
40 $boundary = wp_generate_password ( 24, false );
41 $headers['Content-Type'] = 'multipart/form-data; boundary=' . $boundary;
42 $body = $this->openai->buildFormBody( $forms, $boundary );
43 }
44 else if ( !empty( $json ) ) {
45 $body = json_encode( $json );
46 }
47
48 // Build options
49 $options = array(
50 'headers' => $headers,
51 'method' => 'POST',
52 'timeout' => MWAI_TIMEOUT,
53 'body' => $body,
54 'sslverify' => false
55 );
56
57 return $options;
58 }
59
60 private function runQuery( $url, $options ) {
61 try {
62 $response = wp_remote_get( $url, $options );
63 if ( is_wp_error( $response ) ) {
64 throw new Exception( $response->get_error_message() );
65 }
66 $response = wp_remote_retrieve_body( $response );
67
68 // If Headers contains multipart/form-data then we don't need to decode the response
69 if ( strpos( $options['headers']['Content-Type'], 'multipart/form-data' ) !== false ) {
70 return $response;
71 }
72
73 $data = json_decode( $response, true );
74 $this->openai->handleResponseErrors( $data );
75 return $data;
76 }
77 catch ( Exception $e ) {
78 error_log( $e->getMessage() );
79 throw $e;
80 }
81 }
82
83 private function applyQueryParameters( $query ) {
84 if ( empty( $query->service ) ) {
85 $query->service = $this->localService;
86 }
87
88 // OpenAI will be used by default for everything
89 if ( empty( $query->apiKey ) ) {
90 $query->apiKey = $this->localApiKey;
91 }
92
93 // But if the service is set to Azure and the deployments/models are available,
94 // then we will use Azure instead.
95 if ( $query->service === 'azure' && !empty( $this->localAzureDeployments ) ) {
96 $found = false;
97 foreach ( $this->localAzureDeployments as $deployment ) {
98 if ( $deployment['model'] === $query->model ) {
99 $query->azureDeployment = $deployment['name'];
100 if ( empty( $query->azureEndpoint ) ) {
101 $query->azureEndpoint = $this->localAzureEndpoint;
102 }
103 if ( empty( $query->azureApiKey ) ) {
104 $query->azureApiKey = $this->localAzureApiKey;
105 }
106 $found = true;
107 break;
108 }
109 }
110 if ( !$found ) {
111 error_log( 'Azure deployment not found for model: ' . $query->model );
112 $query->service = 'openai';
113 }
114 }
115 }
116
117 private function getAudio( $url ) {
118 require_once( ABSPATH . 'wp-admin/includes/media.php' );
119 $tmpFile = tempnam( sys_get_temp_dir(), 'audio_' );
120 file_put_contents( $tmpFile, file_get_contents( $url ) );
121 $length = null;
122 $metadata = wp_read_audio_metadata( $tmpFile );
123 if ( isset( $metadata['length'] ) ) {
124 $length = $metadata['length'];
125 }
126 $data = file_get_contents( $tmpFile );
127 unlink( $tmpFile );
128 return [ 'data' => $data, 'length' => $length ];
129 }
130
131 private function runTranscribeQuery( $query ) {
132 $this->applyQueryParameters( $query );
133
134 // Prepare the request
135 $modeEndpoint = $query->mode === 'translation' ? 'translations' : 'transcriptions';
136 $url = 'https://api.openai.com/v1/audio/' . $modeEndpoint;
137 $audioData = $this->getAudio( $query->url );
138 $body = array(
139 'prompt' => $query->prompt,
140 'model' => $query->model,
141 'response_format' => 'text',
142 'file' => basename( $query->url ),
143 'data' => $audioData['data']
144 );
145 $headers = $this->buildHeaders( $query );
146 $options = $this->buildOptions( $headers, null, $body );
147
148 // Perform the request
149 try {
150 $data = $this->runQuery( $url, $options );
151 if ( empty( $data ) ) {
152 throw new Exception( 'Invalid data for transcription.' );
153 }
154 $usage = $this->core->recordAudioUsage( $query->model, $audioData['length'] );
155 $reply = new Meow_MWAI_Reply( $query );
156 $reply->setUsage( $usage );
157 $reply->setChoices( $data );
158 return $reply;
159 }
160 catch ( Exception $e ) {
161 error_log( $e->getMessage() );
162 throw new Exception( 'Error while calling OpenAI: ' . $e->getMessage() );
163 }
164 }
165
166 private function runEmbeddingQuery( $query ) {
167 $this->applyQueryParameters( $query );
168
169 // Prepare the request
170 $url = 'https://api.openai.com/v1/embeddings';
171 $body = array( 'input' => $query->prompt, 'model' => $query->model );
172 if ( $query->service === 'azure' ) {
173 $url = trailingslashit( $query->azureEndpoint ) . 'openai/deployments/' .
174 $query->azureDeployment . '/embeddings?api-version=2023-03-15-preview';
175 $body = array( "input" => $query->prompt );
176 }
177 $headers = $this->buildHeaders( $query );
178 $options = $this->buildOptions( $headers, $body );
179
180 // Perform the request
181 try {
182 $data = $this->runQuery( $url, $options );
183 if ( empty( $data ) || !isset( $data['data'] ) ) {
184 throw new Exception( 'Invalid data for embedding.' );
185 }
186 $usage = $data['usage'];
187 $this->core->recordTokensUsage( $query->model, $usage['prompt_tokens'] );
188 $reply = new Meow_MWAI_Reply( $query );
189 $reply->setUsage( $usage );
190 $reply->setChoices( $data['data'] );
191 return $reply;
192 }
193 catch ( Exception $e ) {
194 error_log( $e->getMessage() );
195 $service = $query->service === 'azure' ? 'Azure' : 'OpenAI';
196 throw new Exception( "Error while calling {$service}: " . $e->getMessage() );
197 }
198 }
199
200 private function runCompletionQuery( $query ) {
201 $this->applyQueryParameters( $query );
202 if ( $query->mode !== 'chat' && $query->mode !== 'completion' ) {
203 throw new Exception( 'Unknown mode for query: ' . $query->mode );
204 }
205
206 // Prepare the request
207 $body = array(
208 "model" => $query->model,
209 "stop" => $query->stop,
210 "n" => $query->maxResults,
211 "max_tokens" => $query->maxTokens,
212 "temperature" => $query->temperature,
213 );
214 if ( $query->mode === 'chat' ) {
215 $body['messages'] = $query->messages;
216 }
217 else if ( $query->mode === 'completion' ) {
218 $body['prompt'] = $query->getPrompt();
219 }
220 $url = $query->service === 'azure' ? trailingslashit( $query->azureEndpoint ) .
221 'openai/deployments/' . $query->azureDeployment : $this->openaiEndpoint;
222 if ( $query->mode === 'chat' ) {
223 $url .= $query->service === 'azure' ? '/chat/completions' . $this->azureApiVersion : '/chat/completions';
224 }
225 else if ($query->mode === 'completion') {
226 $url .= $query->service === 'azure' ? '/completions' . $this->azureApiVersion : '/completions';
227 }
228 $headers = $this->buildHeaders( $query );
229 $options = $this->buildOptions( $headers, $body );
230
231 try {
232 $data = $this->runQuery( $url, $options );
233 if ( !$data['model'] ) {
234 error_log( print_r( $data, 1 ) );
235 throw new Exception( "Got an unexpected response from OpenAI. Check your PHP Error Logs." );
236 }
237 $reply = new Meow_MWAI_Reply( $query );
238 try {
239 $usage = $this->core->recordTokensUsage(
240 $data['model'],
241 $data['usage']['prompt_tokens'],
242 $data['usage']['completion_tokens']
243 );
244 }
245 catch ( Exception $e ) {
246 error_log( $e->getMessage() );
247 }
248 $reply->setUsage( $usage );
249 $reply->setChoices( $data['choices'] );
250 return $reply;
251 }
252 catch ( Exception $e ) {
253 error_log( $e->getMessage() );
254 $service = $query->service === 'azure' ? 'Azure' : 'OpenAI';
255 throw new Exception( "Error while calling {$service}: " . $e->getMessage() );
256 }
257 }
258
259 // Request to DALL-E API
260 private function runImagesQuery( $query ) {
261 $this->applyQueryParameters( $query );
262
263 // Prepare the request
264 $url = 'https://api.openai.com/v1/images/generations';
265 $body = array(
266 "prompt" => $query->prompt,
267 "n" => $query->maxResults,
268 "size" => '1024x1024',
269 );
270 $headers = $this->buildHeaders( $query );
271 $options = $this->buildOptions( $headers, $body );
272
273 // Perform the request
274 try {
275 $data = $this->runQuery( $url, $options );
276 $reply = new Meow_MWAI_Reply( $query );
277 $usage = $this->core->recordImagesUsage( "dall-e", "1024x1024", $query->maxResults );
278 $reply->setUsage( $usage );
279 $reply->setChoices( $data['data'] );
280 $reply->setType( 'images' );
281 return $reply;
282 }
283 catch ( Exception $e ) {
284 error_log( $e->getMessage() );
285 throw new Exception( 'Error while calling OpenAI: ' . $e->getMessage() );
286 }
287 }
288
289 public function run( $query ) {
290 // Check if the query is allowed
291 $limits = $this->core->get_option( 'limits' );
292 $ok = apply_filters( 'mwai_ai_allowed', true, $query, $limits );
293 if ( $ok !== true ) {
294 $message = is_string( $ok ) ? $ok : 'Unauthorized query.';
295 throw new Exception( $message );
296 }
297
298 // Allow to modify the query
299 $query = apply_filters( 'mwai_ai_query', $query );
300 $query->finalChecks();
301
302 // Run the query
303 $reply = null;
304 if ( $query instanceof Meow_MWAI_QueryText ) {
305 $reply = $this->runCompletionQuery( $query );
306 }
307 else if ( $query instanceof Meow_MWAI_QueryEmbed ) {
308 $reply = $this->runEmbeddingQuery( $query );
309 }
310 else if ( $query instanceof Meow_MWAI_QueryImage ) {
311 $reply = $this->runImagesQuery( $query );
312 }
313 else if ( $query instanceof Meow_MWAI_QueryTranscribe ) {
314 $reply = $this->runTranscribeQuery( $query );
315 }
316 else {
317 throw new Exception( 'Unknown query type.' );
318 }
319
320 // Let's allow some modififications of the reply
321 $reply = apply_filters( 'mwai_ai_reply', $reply, $query );
322 return $reply;
323 }
324 }
325