PluginProbe ʕ •ᴥ•ʔ
AI Engine – The Chatbot, AI Framework & MCP for WordPress / 1.8.9
AI Engine – The Chatbot, AI Framework & MCP for WordPress v1.8.9
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
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 bool $isChat = false;
8 public ?string $stop = null;
9 public array $messages = [];
10 public ?string $context = null;
11 public ?string $newMessage = null;
12 public ?string $promptEnding = null;
13 public bool $casuallyFineTuned = false;
14 public ?int $promptTokens = null;
15
16 public function __construct( ?string $prompt = '', int $maxTokens = 1024, string $model = MWAI_DEFAULT_MODEL ) {
17 parent::__construct( $prompt );
18 $this->setModel( $model );
19 $this->setMaxTokens( $maxTokens );
20 }
21
22 public function jsonSerialize() {
23 return [
24 'class' => get_class( $this ),
25 'prompt' => $this->prompt,
26 'messages' => $this->messages,
27 'maxTokens' => $this->maxTokens,
28 'temperature' => $this->temperature,
29 'maxSentences' => $this->maxSentences,
30 'isChat' => $this->isChat,
31 'stop' => $this->stop,
32 'context' => $this->context,
33 'newMessage' => $this->newMessage,
34 'promptEnding' => $this->promptEnding,
35 'casuallyFineTuned' => $this->casuallyFineTuned,
36 'model' => $this->model,
37 'mode' => $this->mode,
38 'session' => $this->session,
39 'env' => $this->env,
40 'service' => $this->service,
41 ];
42 }
43
44 public function getPromptTokens( $refresh = false ): int {
45 if ( $this->promptTokens && !$refresh ) {
46 return $this->promptTokens;
47 }
48 $this->promptTokens = $this->estimateTokens( $this->messages );
49 return $this->promptTokens;
50 }
51
52 public function getLastPrompt(): string {
53 if ( empty( $this->messages ) ) {
54 return $this->prompt;
55 }
56 $lastMessage = end( $this->messages );
57 return $lastMessage['content'];
58 }
59
60 // Quick and dirty token estimation
61 // Let's keep this synchronized with Helpers in JS
62 function estimateTokens( $content ): int
63 {
64 $text = "";
65 // https://github.com/openai/openai-cookbook/blob/main/examples/How_to_count_tokens_with_tiktoken.ipynb
66 if ( is_array( $content ) ) {
67 foreach ( $content as $message ) {
68 $role = $message['role'];
69 $content = $message['content'];
70 $text .= "=#=$role\n$content=#=\n";
71 }
72 }
73 else {
74 $text = $content;
75 }
76 $tokens = 0;
77 return apply_filters( 'mwai_estimate_tokens', (int)$tokens, $text, $this->model );
78 }
79
80 /**
81 * Make sure the maxTokens is not greater than the model's context length.
82 */
83 public function finalChecks() {
84 if ( empty( $this->model ) ) { return; }
85
86 // Make sure the number of messages is not too great
87 if ( !empty( $this->maxSentences ) ) {
88 $context = array_shift( $this->messages );
89 if ( !empty( $this->messages ) ) {
90 $this->messages = array_slice( $this->messages, -$this->maxSentences * 2 );
91 }
92 else {
93 $this->messages = [];
94 }
95 if ( !empty( $context ) ) {
96 array_unshift( $this->messages, $context );
97 }
98 }
99
100 // Make sure the max tokens are respected.
101 $realMax = 4096;
102 $finetuneFamily = preg_match('/^([a-zA-Z]{0,32}):/', $this->model, $matches );
103 $finetuneFamily = ( isset( $matches ) && count( $matches ) > 0 ) ? $matches[1] : 'N/A';
104 $foundModel = null;
105 $openai_models = Meow_MWAI_Engines_OpenAI::get_openai_models();
106 foreach ( $openai_models as $currentModel ) {
107 if ( $currentModel['model'] === $this->model || $currentModel['family'] === $finetuneFamily ) {
108 $foundModel = $currentModel['name'];
109 $realMax = $currentModel['maxTokens'];
110 break;
111 }
112 }
113 $estimatedTokens = $this->getPromptTokens();
114 if ( !empty( $realMax ) && $estimatedTokens > $realMax ) {
115 throw new Exception( "AI Engine: The prompt is too long! It contains about $estimatedTokens tokens (estimation). The $foundModel model only accepts a maximum of $realMax tokens. " );
116 }
117 $realMax = (int)($realMax - $estimatedTokens) - 16;
118 if ( $this->maxTokens > $realMax ) {
119 $this->maxTokens = $realMax;
120 }
121 }
122
123 /**
124 * ID of the model to use.
125 * @param string $model ID of the model to use.
126 */
127 public function setModel( string $model ) {
128 $this->model = $model;
129 $this->mode = 'completion';
130 $openai_models = Meow_MWAI_Engines_OpenAI::get_openai_models();
131 foreach ( $openai_models as $currentModel ) {
132 if ( $currentModel['model'] === $this->model ) {
133 if ( $currentModel['mode'] ) {
134 $this->mode = $currentModel['mode'];
135 }
136 break;
137 }
138 }
139 }
140
141 /**
142 * Given a prompt, the model will return one or more predicted completions.
143 * It can also return the probabilities of alternative tokens at each position.
144 * @param string $prompt The prompt to generate completions.
145 */
146 public function setPrompt( $prompt ) {
147 parent::setPrompt( $prompt );
148 $this->validateMessages();
149 }
150
151 /**
152 * The prompt is used by models who uses Text Completion (and not Chat Completion).
153 * This returns the prompt if it's not a chat, otherwise it will build a prompt with
154 * all the messages nicely formatted.
155 */
156 public function getPrompt(): ?string {
157 if ( !$this->isChat ) {
158 return $this->prompt . $this->promptEnding;
159 }
160
161 $first = reset( $this->messages );
162 $prompt = "";
163 if ( $first && $first['role'] === 'system' ) {
164 $prompt = $first['content'] . "\n\n";
165 }
166
167 // Casually Fine-Tuned or Prompt-Ending
168 if ( !empty( $this->promptEnding ) ) {
169 $last = end( $this->messages );
170 if ( $last && $last['role'] === 'user' ) {
171 $prompt = $last['content'] . $this->promptEnding;
172 }
173 return $prompt;
174 }
175
176 // Standard Completion
177 while ( $message = next( $this->messages ) ) {
178 $role = $message['role'];
179 $content = $message['content'];
180 if ( $role === 'system' ) {
181 $prompt .= "$content\n\n";
182 }
183 if ( $role === 'user' ) {
184 $prompt .= "User: $content\n";
185 }
186 if ( $role === 'assistant' ) {
187 $prompt .= "AI: $content\n";
188 }
189 }
190 $prompt .= "AI: ";
191 return $prompt;
192 }
193
194 /**
195 * Similar to the prompt, but focus on the new/last message.
196 * Only used when the model has a chat mode (and only used in messages).
197 * @param string $prompt The messages to generate completions.
198 */
199 public function setNewMessage( string $newMessage ): void {
200 $this->newMessage = $newMessage;
201 $this->validateMessages();
202 }
203
204 public function replace( $search, $replace ) {
205 $this->prompt = str_replace( $search, $replace, $this->prompt );
206 $this->validateMessages();
207 }
208
209 public function setIsChat( $isChat ) {
210 $this->isChat = $isChat;
211 }
212
213 /**
214 * Similar to the prompt, but use an array of messages instead.
215 * @param string $prompt The messages to generate completions.
216 */
217 public function setMessages( array $messages ) {
218 $messages = array_map( function( $message ) {
219 return [ 'role' => $message['role'], 'content' => $message['content'] ];
220 }, $messages );
221 $this->messages = $messages;
222 $this->validateMessages();
223 }
224
225 public function getLastMessage(): ?string {
226 if ( !empty( $this->messages ) ) {
227 $lastMessageIndex = count( $this->messages ) - 1;
228 $lastMessage = $this->messages[$lastMessageIndex];
229 return $lastMessage['content'];
230 }
231 return null;
232 }
233
234 // Function that adds a message just before the last message
235 public function injectContext( string $content ): void {
236 if ( !empty( $this->messages ) ) {
237 $lastMessageIndex = count( $this->messages ) - 1;
238 $lastMessage = $this->messages[$lastMessageIndex];
239 $this->messages[$lastMessageIndex] = [ 'role' => 'system', 'content' => $content ];
240 array_push( $this->messages, $lastMessage );
241 }
242 $this->validateMessages();
243 }
244
245 /**
246 * The context that is used for the chat completion (mode === 'chat').
247 * @param string $context The context to use.
248 */
249 public function setContext( string $context ): void {
250 $this->context = apply_filters( 'mwai_ai_context', $context, $this );
251 $this->validateMessages();
252 }
253
254 private function validateMessages(): void {
255 // Messages should end with either the prompt or, if exists, the newMessage.
256 $message = empty( $this->newMessage ) ? $this->prompt : $this->newMessage;
257 if ( empty( $this->messages ) ) {
258 $this->messages = [ [ 'role' => 'user', 'content' => $message ] ];
259 }
260 else {
261 $last = &$this->messages[ count( $this->messages ) - 1 ];
262 if ( $last['role'] === 'user' ) {
263 $last['content'] = $message;
264 }
265 else {
266 array_push( $this->messages, [ 'role' => 'user', 'content' => $message ] );
267 }
268 }
269
270 // The main context must be first.
271 if ( !empty( $this->context ) ) {
272 if ( is_array( $this->messages ) && count( $this->messages ) > 0 ) {
273 if ( $this->messages[0]['role'] !== 'system' ) {
274 array_unshift( $this->messages, [ 'role' => 'system', 'content' => $this->context ] );
275 }
276 else {
277 $this->messages[0]['content'] = $this->context;
278 }
279 }
280 }
281 }
282
283 /**
284 * The maximum number of tokens to generate in the completion.
285 * The token count of your prompt plus max_tokens cannot exceed the model's context length.
286 * Most models have a context length of 2048 tokens (except for the newest models, which support 4096).
287 * @param float $prompt The maximum number of tokens.
288 */
289 public function setMaxTokens( int $maxTokens ): void {
290 $this->maxTokens = $maxTokens;
291 }
292
293 /**
294 * Set the sampling temperature to use. Higher values means the model will take more risks.
295 * Try 0.9 for more creative applications, and 0 for ones with a well-defined reply.
296 * @param float $temperature The temperature.
297 */
298 public function setTemperature( float $temperature ): void {
299 $temperature = floatval( $temperature );
300 if ( $temperature > 1 ) {
301 $temperature = 1;
302 }
303 if ( $temperature < 0 ) {
304 $temperature = 0;
305 }
306 $this->temperature = round( $temperature, 2 );
307 }
308
309 public function setMaxSentences( int $maxSentences ): void {
310 if ( !empty( $maxSentences ) ) {
311 $this->maxSentences = intval( $maxSentences );
312 $this->validateMessages();
313 }
314 }
315
316 public function setStop( string $stop ): void {
317 $this->stop = $stop;
318 }
319
320 private function convertKeys( $params )
321 {
322 $newParams = [];
323 foreach ( $params as $key => $value ) {
324 $newKey = '';
325 $capitalizeNextChar = false;
326 for ( $i = 0; $i < strlen( $key ); $i++ ) {
327 if ( $key[$i] == '_' ) {
328 $capitalizeNextChar = true;
329 }
330 else {
331 $newKey .= $capitalizeNextChar ? strtoupper($key[$i]) : $key[$i];
332 $capitalizeNextChar = false;
333 }
334 }
335 $newParams[$newKey] = $value;
336 }
337 return $newParams;
338 }
339
340 // Based on the params of the query, update the attributes
341 public function injectParams( array $params ): void
342 {
343 // Those are for the keys passed directly by the shortcode.
344 $params = $this->convertKeys( $params );
345
346 $acceptedValues = [ true, 1, '1' ];
347 if ( !empty( $params['model'] ) ) {
348 $this->setModel( $params['model'] );
349 }
350 if ( !empty( $params['casuallyFineTuned'] ) && in_array( $params['casuallyFineTuned'], $acceptedValues, true ) ) {
351 $this->promptEnding = "\n\n###\n\n";
352 $this->stop = "\n\n";
353 $this->casuallyFineTuned = true;
354 }
355 if ( !empty( $params['prompt'] ) ) {
356 $this->setPrompt( $params['prompt'] );
357 }
358 if ( !empty( $params['context'] ) ) {
359 $this->setContext( $params['context'] );
360 }
361 if ( !empty( $params['messages'] ) ) {
362 $this->setMessages( $params['messages'] );
363 }
364 if ( !empty( $params['newMessage'] ) ) {
365 $this->setNewMessage( $params['newMessage'] );
366 }
367 if ( !empty( $params['maxTokens'] ) && intval( $params['maxTokens'] ) > 0 ) {
368 $this->setMaxTokens( intval( $params['maxTokens'] ) );
369 }
370 if ( !empty( $params['maxMessages'] ) && intval( $params['maxMessages'] ) > 0 ) {
371 $this->setMaxSentences( intval( $params['maxMessages'] ) );
372 }
373 if ( !empty( $params['maxSentences'] ) && intval( $params['maxSentences'] ) > 0 ) {
374 $this->setMaxSentences( intval( $params['maxSentences'] ) );
375 }
376 if ( !empty( $params['temperature'] ) ) {
377 $this->setTemperature( $params['temperature'] );
378 }
379 if ( !empty( $params['stop'] ) ) {
380 $this->setStop( $params['stop'] );
381 }
382 if ( !empty( $params['maxResults'] ) ) {
383 $this->setMaxResults( $params['maxResults'] );
384 }
385 if ( !empty( $params['env'] ) ) {
386 $this->setEnv( $params['env'] );
387 }
388 if ( !empty( $params['session'] ) ) {
389 $this->setSession( $params['session'] );
390 }
391 // Should add the params related to Open AI and Azure
392 if ( !empty( $params['service'] ) ) {
393 $this->setService( $params['service'] );
394 }
395 if ( !empty( $params['apiKey'] ) ) {
396 $this->setApiKey( $params['apiKey'] );
397 }
398 if ( !empty( $params['botId'] ) ) {
399 $this->setBotId( $params['botId'] );
400 }
401 }
402 }