PluginProbe ʕ •ᴥ•ʔ
AI Engine – The Chatbot, AI Framework & MCP for WordPress / 2.2.4
AI Engine – The Chatbot, AI Framework & MCP for WordPress v2.2.4
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 / engines / core.php
ai-engine / classes / engines Last commit date
anthropic.php 2 years ago core.php 2 years ago factory.php 2 years ago google.php 2 years ago huggingface.php 2 years ago openai.php 2 years ago openrouter.php 2 years ago
core.php
315 lines
1 <?php
2
3 class Meow_MWAI_Engines_Core {
4 protected $core = null;
5 public $env = null;
6 public $envId = null;
7 public $envType = null;
8
9 // Streaming
10 protected $streamCallback = null;
11 protected $streamTemporaryBuffer = "";
12 protected $streamBuffer = "";
13 protected $streamHeaders = [];
14 protected $streamContent = "";
15
16 public function __construct( $core, $env ) {
17 $this->core = $core;
18 $this->env = $env;
19 $this->envId = $env['id'];
20 $this->envType = $env['type'];
21 }
22
23 public function run( $query, $streamCallback = null ) {
24
25 // Check if the query is allowed.
26 $limits = $this->core->get_option( 'limits' );
27 $allowed = apply_filters( 'mwai_ai_allowed', true, $query, $limits );
28 if ( $allowed !== true ) {
29 $message = is_string( $allowed ) ? $allowed : 'Unauthorized query.';
30 throw new Exception( $message );
31 }
32
33 // Allow to modify the query before it is sent. It should not be a Meow_MWAI_Query_Embed.
34 if ( !( $query instanceof Meow_MWAI_Query_Embed ) ) {
35 $query = apply_filters( 'mwai_ai_query', $query );
36 }
37
38 // Important as it makes sure everything is consolidated in the query and the engine.
39 $this->final_checks( $query );
40
41 // Run the query
42 $reply = null;
43 if ( $query instanceof Meow_MWAI_Query_Text ) {
44 $reply = $this->run_completion_query( $query, $streamCallback );
45 }
46 else if ( $query instanceof Meow_MWAI_Query_Assistant ) {
47 $reply = null;
48 $reply = apply_filters( 'mwai_ai_query_assistant', $reply, $query );
49 if ( $reply === null ) {
50 throw new Exception( 'Assistants are not supported in this version of AI Engine.' );
51 }
52 }
53 else if ( $query instanceof Meow_MWAI_Query_Embed ) {
54 $reply = $this->run_embedding_query( $query );
55 }
56 else if ( $query instanceof Meow_MWAI_Query_Image ) {
57 $reply = $this->run_images_query( $query );
58 }
59 else if ( $query instanceof Meow_MWAI_Query_Transcribe ) {
60 $reply = $this->run_transcribe_query( $query );
61 }
62 else {
63 throw new Exception( 'Unknown query type.' );
64 }
65
66 // Allow to modify the reply before it is sent.
67 $reply = apply_filters( 'mwai_ai_reply', $reply, $query );
68
69 return $reply;
70 }
71
72 public function retrieve_model_info( $model ) {
73 $models = $this->get_models();
74 foreach ( $models as $currentModel ) {
75 if ( $currentModel['model'] === $model ) {
76 return $currentModel;
77 }
78 }
79 return false;
80 }
81
82 public function final_checks( Meow_MWAI_Query_Base $query ) {
83 $query->final_checks();
84 //$found = false;
85
86 // Check if the model is available, except if it's an assistant
87 if ( !( $query instanceof Meow_MWAI_Query_Assistant ) ) {
88 // TODO: Avoid checking on the finetuned models for now.
89 if ( substr( $query->model, 0, 3 ) === 'ft:' ) {
90 return;
91 }
92 $model_info = $this->retrieve_model_info( $query->model );
93 if ( $model_info === false ) {
94 throw new Exception( "AI Engine: The model '{$query->model}' is not available." );
95 }
96 if ( isset( $model_info['mode'] ) ) {
97 $query->mode = $model_info['mode'];
98 }
99 }
100 }
101
102 // Streamline the messages:
103 // - Concatenate consecutive model messages into a single message for the model role
104 // - Make sure the first message is a user message
105 // - Make sure the last message is a user message
106 protected function streamline_messages( $messages, $systemRole = 'assistant', $messageType = 'content' )
107 {
108 $processedMessages = [];
109 $lastRole = '';
110 $concatenatedText = '';
111
112 // Determine the way to access message content based on messageType
113 $getContent = function( $message ) use ( $messageType ) {
114 if ( $messageType == 'parts' ) {
115 return $message['parts'][0]['text'];
116 }
117 else { // Default to 'content'
118 return $message['content'];
119 }
120 };
121
122 // Set content to a message depending on the messageType
123 $setContent = function( &$message, $content ) use ( $messageType ) {
124 if ( $messageType == 'parts' ) {
125 $message['parts'] = [['text' => $content]];
126 }
127 else { // Default to 'content'
128 $message['content'] = $content;
129 }
130 };
131
132 // Concatenate consecutive model messages into a single message for the model role
133 foreach ( $messages as $message ) {
134 if ( $message['role'] == $systemRole ) {
135 if ( $lastRole == $systemRole ) {
136 $concatenatedText .= "\n" . $getContent( $message );
137 }
138 else {
139 if ( $concatenatedText !== '' ) {
140 $newMessage = [ 'role' => $systemRole ];
141 $setContent( $newMessage, $concatenatedText );
142 $processedMessages[] = $newMessage;
143 }
144 $concatenatedText = $getContent( $message );
145 }
146 }
147 else {
148 if ( $lastRole == $systemRole ) {
149 $newMessage = [ 'role' => $systemRole ];
150 $setContent( $newMessage, $concatenatedText );
151 $processedMessages[] = $newMessage;
152 $concatenatedText = '';
153 }
154 $processedMessages[] = $message;
155 }
156 $lastRole = $message['role'];
157 }
158 if ( $lastRole == $systemRole && $concatenatedText !== '' ) {
159 $newMessage = [ 'role' => $systemRole ];
160 $setContent( $newMessage, $concatenatedText );
161 $processedMessages[] = $newMessage;
162 }
163
164 // Make sure the last message is a user message, if not, throw an exception
165 if ( end( $processedMessages )['role'] !== 'user' ) {
166 throw new Exception( 'The last message must be a user message.' );
167 }
168
169 // Make sure the first message is a user message, if not, add an empty user message
170 if ( $processedMessages[0]['role'] !== 'user' ) {
171 $newMessage = [ 'role' => 'user' ];
172 $setContent( $newMessage, '' );
173 array_unshift( $processedMessages, $newMessage );
174 }
175
176 return $processedMessages;
177 }
178
179 // Check for a JSON-formatted error in the data, and throw an exception if it's the case.
180 function stream_error_check( $data ) {
181 if ( strpos( $data, 'error' ) === false ) {
182 return;
183 }
184 $data = trim( $data );
185 $jsonPart = $data;
186 if ( strpos( $jsonPart, 'data:' ) === 0 ) {
187 $jsonPart = trim( substr( $jsonPart, strlen( 'data:' ) ) );
188 }
189 $json = json_decode( $jsonPart, true );
190 if ( json_last_error() === JSON_ERROR_NONE ) {
191 if ( isset( $json['error'] ) ) {
192 $error = $json['error'];
193 $code = null;
194 $type = null;
195 $message = null;
196 if ( isset( $error['message'] ) ) {
197 $message = $error['message'];
198 }
199 else if ( is_string( $error ) ) {
200 throw new Exception( "Error: $error" );
201 }
202 else {
203 throw new Exception( "Unknown error (stream_error_check)." );
204 }
205 if ( isset( $error['code'] ) ) {
206 $code = $error['code'];
207 }
208 if ( isset( $error['type'] ) ) {
209 $type = $error['type'];
210 }
211 $errorMessage = "Error: $message";
212 if ( !is_null( $code ) ) {
213 $errorMessage .= " ($code)";
214 }
215 if ( !is_null( $type ) ) {
216 $errorMessage .= " ($type)";
217 }
218 throw new Exception( $errorMessage );
219 }
220 else if ( isset( $json['type'] ) && $json['type'] === 'error' ) {
221 $type = $json['error']['type'];
222 $message = $json['error']['message'];
223 throw new Exception( "Error: $message ($type)" );
224 }
225 }
226 }
227
228 public function stream_handler( $handle, $args, $url ) {
229 curl_setopt( $handle, CURLOPT_SSL_VERIFYPEER, false );
230 curl_setopt( $handle, CURLOPT_SSL_VERIFYHOST, false );
231
232 // TODO: This is breaking the response. We need to find a way to handle the headers.
233 // curl_setopt( $handle, CURLOPT_HEADERFUNCTION, function ( $curl, $header ) {
234 // $length = strlen( $header );
235 // $this->streamHeaders[] = $header;
236 // $this->stream_header_handler( $header );
237 // return $length;
238 // });
239
240 curl_setopt( $handle, CURLOPT_WRITEFUNCTION, function ( $curl, $data ) {
241 $length = strlen( $data );
242
243 // Error Management
244 $this->stream_error_check( $data );
245
246 // Bufferize the unfinished stream (if it's the case)
247 $this->streamTemporaryBuffer .= $data;
248 $this->streamBuffer .= $data;
249 $lines = explode( "\n", $this->streamTemporaryBuffer );
250 if ( substr( $this->streamTemporaryBuffer, -1 ) !== "\n" ) {
251 $this->streamTemporaryBuffer = array_pop( $lines );
252 }
253 else {
254 $this->streamTemporaryBuffer = "";
255 }
256
257 foreach ( $lines as $line ) {
258 if ( $line === "" ) { continue; }
259 if ( strpos( $line, 'data:' ) === 0 ) {
260 $line = trim( substr( $line, 5 ) );
261 $json = json_decode( trim( $line ), true );
262
263 if ( json_last_error() === JSON_ERROR_NONE ) {
264 $content = $this->stream_data_handler( $json );
265 if ( !is_null( $content ) ) {
266 $this->streamContent .= $content;
267 call_user_func( $this->streamCallback, $content );
268 }
269 }
270 else if ( $line !== '[DONE]' && !empty( $line ) ) {
271 $this->streamTemporaryBuffer .= $line . "\n";
272 }
273 }
274 }
275 return $length;
276 });
277 }
278
279 protected function stream_header_handler( $header ) {
280
281 }
282
283 protected function stream_data_handler( $json ) {
284 throw new Exception( 'Not implemented.' );
285 }
286
287 public function get_models() {
288 throw new Exception( 'Not implemented.' );
289 }
290
291 public function retrieve_models() {
292 throw new Exception( 'Not implemented.' );
293 }
294
295 public function run_completion_query( Meow_MWAI_Query_Base $query, $streamCallback = null ) : Meow_MWAI_Reply {
296 throw new Exception( 'Not implemented.' );
297 }
298
299 public function run_embedding_query( Meow_MWAI_Query_Base $query ) {
300 throw new Exception( 'Not implemented.' );
301 }
302
303 public function run_images_query( Meow_MWAI_Query_Base $query ) {
304 throw new Exception( 'Not implemented.' );
305 }
306
307 public function run_transcribe_query( Meow_MWAI_Query_Base $query ) {
308 throw new Exception( 'Not implemented.' );
309 }
310
311 public function get_price( Meow_MWAI_Query_Base $query, Meow_MWAI_Reply $reply ) {
312 throw new Exception( 'Not implemented.' );
313 }
314 }
315