PluginProbe ʕ •ᴥ•ʔ
AI Engine – The Chatbot, AI Framework & MCP for WordPress / 2.0.8
AI Engine – The Chatbot, AI Framework & MCP for WordPress v2.0.8
3.6.2 3.6.1 3.6.0 3.5.9 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 / queries / text.php
ai-engine / classes / queries Last commit date
assistant.php 2 years ago base.php 2 years ago embed.php 2 years ago function.php 2 years ago image.php 2 years ago parameter.php 2 years ago text.php 2 years ago transcribe.php 2 years ago
text.php
402 lines
1 <?php
2
3 class Meow_MWAI_Query_Text extends Meow_MWAI_Query_Base implements JsonSerializable {
4 public int $maxTokens = 1024;
5 public float $temperature = 0.8;
6 public int $maxSentences = 15;
7 public ?string $stop = null;
8 public array $messages = [];
9 public ?string $context = null;
10 public ?string $newMessage = null;
11 public ?string $newImage = null;
12 public ?string $newImageData = null;
13 public ?string $responseFormat = null;
14 public ?int $promptTokens = null;
15
16 public function __construct( ?string $prompt = '', int $maxTokens = 1024,
17 string $model = MWAI_FALLBACK_MODEL ) {
18 parent::__construct( $prompt );
19 $this->set_model( $model );
20 $this->set_max_tokens( $maxTokens );
21 }
22
23 #[\ReturnTypeWillChange]
24 public function jsonSerialize() {
25 return [
26 'class' => get_class( $this ),
27 'prompt' => $this->prompt,
28 'messages' => $this->messages,
29 'maxTokens' => $this->maxTokens,
30 'temperature' => $this->temperature,
31 'maxSentences' => $this->maxSentences,
32 'context' => $this->context,
33 'newMessage' => $this->newMessage,
34 'newImage' => $this->newImage,
35 'model' => $this->model,
36 'mode' => $this->mode,
37 'session' => $this->session,
38 'env' => $this->env,
39 'envId' => $this->envId,
40 'service' => $this->service,
41 'stop' => $this->stop
42 ];
43 }
44
45 public function get_prompt_tokens( $refresh = false ): int {
46 if ( $this->promptTokens && !$refresh ) {
47 return $this->promptTokens;
48 }
49 $this->promptTokens = Meow_MWAI_Core::estimate_tokens( $this->messages );
50 return $this->promptTokens;
51 }
52
53 public function get_last_prompt(): string {
54 if ( empty( $this->messages ) ) {
55 return $this->prompt;
56 }
57 $last = $this->get_last_message();
58 return $last;
59 }
60
61 /**
62 * Make sure the maxTokens is not greater than the model's context length.
63 */
64 public function final_checks() {
65 if ( empty( $this->model ) ) { return; }
66
67 // Make sure the number of messages is not too great.
68 if ( !empty( $this->maxSentences ) ) {
69 $context = array_shift( $this->messages );
70 if ( !empty( $this->messages ) ) {
71 $this->messages = array_slice( $this->messages, -$this->maxSentences );
72 }
73 else {
74 $this->messages = [];
75 }
76 if ( !empty( $context ) ) {
77 array_unshift( $this->messages, $context );
78 }
79 }
80 }
81
82 /**
83 * ID of the model to use.
84 * @param string $model ID of the model to use.
85 */
86 public function set_model( string $model ) {
87 $this->model = $model;
88 $this->mode = 'completion';
89 $found = false;
90 $openai_models = Meow_MWAI_Engines_OpenAI::get_openai_models();
91 foreach ( $openai_models as $currentModel ) {
92 if ( $currentModel['model'] === $this->model ) {
93 if ( $currentModel['mode'] ) {
94 $this->mode = $currentModel['mode'];
95 }
96 $found = true;
97 break;
98 }
99 }
100 if ( !$found ) {
101 // If the model can't be found, it's because it's probably a fine-tuned model. In the past (before August 2023),
102 // fine-tuned models were always based on GPT-3 (and therefore, using completion mode). From now on, they can be
103 // based on GPT-3.5 or 4 (and therefore, using chat mode). We need to detect that.
104 $baseModel = Meow_MWAI_Engines_OpenAI::get_finetune_base_model( $model );
105 if ( preg_match( '/^gpt-3.5|^gpt-4/', $baseModel ) ) {
106 $this->mode = 'chat';
107 }
108 }
109 }
110
111 /**
112 * Given a prompt, the model will return one or more predicted completions.
113 * It can also return the probabilities of alternative tokens at each position.
114 * @param string $prompt The prompt to generate completions.
115 */
116 public function set_prompt( $prompt ) {
117 parent::set_prompt( $prompt );
118 $this->validate_messages();
119 }
120
121 /**
122 * The type of return expected from the API. It can be either null or "json".
123 * @param int $maxResults The maximum number of completions.
124 */
125 public function set_response_format( $responseFormat ) {
126 if ( !empty( $responseFormat ) && $responseFormat !== 'json' ) {
127 throw new Exception( "AI Engine: The response format can only be null or json." );
128 }
129 $this->responseFormat = $responseFormat;
130 }
131
132 /**
133 * The prompt is used by models who uses Text Completion (and not Chat Completion).
134 * This returns the prompt if it's not a chat, otherwise it will build a prompt with
135 * all the messages nicely formatted.
136 */
137 public function get_prompt(): ?string {
138 // In the case it's really just a prompt.
139 if ( count( $this->messages ) === 1 ) {
140 $first = reset( $this->messages );
141 return $first['content'];
142 }
143
144 // In the case it's a chat that we need to convert into a prompt.
145 $first = reset( $this->messages );
146 $prompt = "";
147 if ( $first && $first['role'] === 'system' ) {
148 $prompt = $first['content'] . "\n\n";
149 }
150
151 // Standard Completion
152 while ( $message = next( $this->messages ) ) {
153 $role = $message['role'];
154 $content = $message['content'];
155 if ( $role === 'system' ) {
156 $prompt .= "$content\n\n";
157 }
158 if ( $role === 'user' ) {
159 $prompt .= "User: $content\n";
160 }
161 if ( $role === 'assistant' ) {
162 $prompt .= "AI: $content\n";
163 }
164 }
165 $prompt .= "AI: ";
166 return $prompt;
167 }
168
169 /**
170 * Similar to the prompt, but focus on the new/last message.
171 * Only used when the model has a chat mode (and only used in messages).
172 * @param string $prompt The messages to generate completions.
173 */
174 public function set_new_message( string $newMessage ): void {
175 $this->newMessage = $newMessage;
176 $this->validate_messages();
177 }
178
179 public function set_new_image( string $newImage ): void {
180 $this->newImage = $newImage;
181 $this->validate_messages();
182 }
183
184 public function set_new_image_data( string $newImageData ): void {
185 $this->newImageData = $newImageData;
186 $this->validate_messages();
187 }
188
189 public function replace( $search, $replace ) {
190 $this->prompt = str_replace( $search, $replace, $this->prompt );
191 $this->validate_messages();
192 }
193
194 /**
195 * Similar to the prompt, but use an array of messages instead.
196 * @param string $prompt The messages to generate completions.
197 */
198 public function set_messages( array $messages ) {
199 $messages = array_map( function( $message ) {
200 if ( is_array( $message ) ) {
201 return [ 'role' => $message['role'], 'content' => $message['content'] ];
202 }
203 else if ( is_object( $message ) ) {
204 return [ 'role' => $message->role, 'content' => $message->content ];
205 }
206 else {
207 throw new InvalidArgumentException( 'Unsupported message type.' );
208 }
209 }, $messages );
210 $this->messages = $messages;
211 $this->validate_messages();
212 }
213
214 public function get_last_message() {
215 if ( !empty( $this->messages ) ) {
216 $lastMessageIndex = count( $this->messages ) - 1;
217 $lastMessage = $this->messages[$lastMessageIndex];
218 if ( is_array( $lastMessage['content'] ) ) {
219 foreach( $lastMessage['content'] as $message ) {
220 if ( $message['type'] === 'text' ) {
221 return $message['text'];
222 }
223 }
224 }
225 else {
226 return $lastMessage['content'];
227 }
228 }
229 return null;
230 }
231
232 // Function that adds a message just before the last message
233 public function inject_context( string $content ): void {
234 if ( !empty( $this->messages ) ) {
235 $lastMessageIndex = count( $this->messages ) - 1;
236 $lastMessage = $this->messages[$lastMessageIndex];
237 $this->messages[$lastMessageIndex] = [ 'role' => 'system', 'content' => $content ];
238 array_push( $this->messages, $lastMessage );
239 }
240 $this->validate_messages();
241 }
242
243 /**
244 * The context that is used for the chat completion (mode === 'chat').
245 * @param string $context The context to use.
246 */
247 public function setContext( string $context ): void {
248 $this->context = apply_filters( 'mwai_ai_context', $context, $this );
249 $this->validate_messages();
250 }
251
252 private function getImageURL( $image ) {
253 if ( !empty( $this->newImage ) ) {
254 return $this->newImage;
255 }
256 if ( !empty( $this->newImageData ) ) {
257 return "data:image/jpeg;base64,{$this->newImageData}";
258 }
259 }
260
261
262 private function validate_messages(): void {
263 // Messages should end with either the prompt or, if exists, the newMessage.
264 $message = empty( $this->newMessage ) ? $this->prompt : $this->newMessage;
265 $content = $message;
266
267 // If there is an image, we need to adapt it to Vision.
268 $imageURL = $this->getImageURL( $this->newImage );
269 if ( !empty( $imageURL ) ) {
270 $content = [
271 [ "type" => "text", "text" => $message ],
272 [ "type" => "image_url", "image_url" => [ "url" => $imageURL ] ]
273 ];
274 }
275
276 if ( empty( $this->messages ) ) {
277 $this->messages = [ [ 'role' => 'user', 'content' => $content ] ];
278 }
279 else {
280 $last = &$this->messages[ count( $this->messages ) - 1 ];
281 if ( $last['role'] === 'user' ) {
282 $last['content'] = $content;
283 }
284 else {
285 array_push( $this->messages, [ 'role' => 'user', 'content' => $content ] );
286 }
287 }
288
289 // The main context must be first.
290 if ( !empty( $this->context ) ) {
291 if ( is_array( $this->messages ) && count( $this->messages ) > 0 ) {
292 if ( $this->messages[0]['role'] !== 'system' ) {
293 array_unshift( $this->messages, [ 'role' => 'system', 'content' => $this->context ] );
294 }
295 else {
296 $this->messages[0]['content'] = $this->context;
297 }
298 }
299 }
300 }
301
302 /**
303 * The maximum number of tokens to generate in the completion.
304 * The token count of your prompt plus max_tokens cannot exceed the model's context length.
305 * Most models have a context length of 2048 tokens (except for the newest models, which support 4096).
306 * @param float $prompt The maximum number of tokens.
307 */
308 public function set_max_tokens( int $maxTokens ): void {
309 $this->maxTokens = $maxTokens;
310 }
311
312 /**
313 * Set the sampling temperature to use. Higher values means the model will take more risks.
314 * Try 0.9 for more creative applications, and 0 for ones with a well-defined reply.
315 * @param float $temperature The temperature.
316 */
317 public function set_temperature( float $temperature ): void {
318 $temperature = floatval( $temperature );
319 if ( $temperature > 1 ) {
320 $temperature = 1;
321 }
322 if ( $temperature < 0 ) {
323 $temperature = 0;
324 }
325 $this->temperature = round( $temperature, 2 );
326 }
327
328 public function set_max_sentences( int $maxSentences ): void {
329 if ( !empty( $maxSentences ) ) {
330 $this->maxSentences = intval( $maxSentences );
331 $this->validate_messages();
332 }
333 }
334
335 public function set_stop( string $stop ): void {
336 $this->stop = $stop;
337 }
338
339 // Based on the params of the query, update the attributes
340 public function inject_params( array $params ): void
341 {
342 // Those are for the keys passed directly by the shortcode.
343 $params = $this->convert_keys( $params );
344
345 $acceptedValues = [ true, 1, '1' ];
346 if ( !empty( $params['model'] ) ) {
347 $this->set_model( $params['model'] );
348 }
349 if ( !empty( $params['prompt'] ) ) {
350 $this->set_prompt( $params['prompt'] );
351 }
352 if ( !empty( $params['context'] ) ) {
353 $this->setContext( $params['context'] );
354 }
355 if ( !empty( $params['messages'] ) ) {
356 $this->set_messages( $params['messages'] );
357 }
358 if ( !empty( $params['newMessage'] ) ) {
359 $this->set_new_message( $params['newMessage'] );
360 }
361 if ( !empty( $params['maxTokens'] ) && intval( $params['maxTokens'] ) > 0 ) {
362 $this->set_max_tokens( intval( $params['maxTokens'] ) );
363 }
364 if ( !empty( $params['maxMessages'] ) && intval( $params['maxMessages'] ) > 0 ) {
365 $this->set_max_sentences( intval( $params['maxMessages'] ) );
366 }
367 if ( !empty( $params['maxSentences'] ) && intval( $params['maxSentences'] ) > 0 ) {
368 $this->set_max_sentences( intval( $params['maxSentences'] ) );
369 }
370 if ( !empty( $params['temperature'] ) ) {
371 $this->set_temperature( $params['temperature'] );
372 }
373 if ( !empty( $params['stop'] ) ) {
374 $this->set_stop( $params['stop'] );
375 }
376 if ( !empty( $params['maxResults'] ) ) {
377 $this->set_max_results( $params['maxResults'] );
378 }
379 if ( !empty( $params['env'] ) ) {
380 $this->set_env( $params['env'] );
381 }
382 if ( !empty( $params['session'] ) ) {
383 $this->set_session( $params['session'] );
384 }
385 // Should add the params related to Open AI and Azure
386 if ( !empty( $params['service'] ) ) {
387 $this->set_service( $params['service'] );
388 }
389 if ( !empty( $params['apiKey'] ) ) {
390 $this->set_api_key( $params['apiKey'] );
391 }
392 if ( !empty( $params['botId'] ) ) {
393 $this->set_bot_id( $params['botId'] );
394 }
395 if ( !empty( $params['envId'] ) ) {
396 $this->set_env_id( $params['envId'] );
397 }
398 if ( !empty( $params['responseFormat'] ) ) {
399 $this->set_response_format( $params['responseFormat'] );
400 }
401 }
402 }