PluginProbe ʕ •ᴥ•ʔ
AI Engine – The Chatbot, AI Framework & MCP for WordPress / 1.7.2
AI Engine – The Chatbot, AI Framework & MCP for WordPress v1.7.2
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
base.php 3 years ago embed.php 3 years ago image.php 3 years ago text.php 3 years ago transcribe.php 3 years ago
text.php
397 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 foreach ( MWAI_OPENAI_MODELS as $currentModel ) {
106 if ( $currentModel['model'] === $this->model || $currentModel['family'] === $finetuneFamily ) {
107 $foundModel = $currentModel['name'];
108 $realMax = $currentModel['maxTokens'];
109 break;
110 }
111 }
112 $estimatedTokens = $this->getPromptTokens();
113 if ( !empty( $realMax ) && $estimatedTokens > $realMax ) {
114 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. " );
115 }
116 $realMax = (int)($realMax - $estimatedTokens) - 16;
117 if ( $this->maxTokens > $realMax ) {
118 $this->maxTokens = $realMax;
119 }
120 }
121
122 /**
123 * ID of the model to use.
124 * @param string $model ID of the model to use.
125 */
126 public function setModel( string $model ) {
127 $this->model = $model;
128 $this->mode = 'completion';
129 foreach ( MWAI_OPENAI_MODELS as $currentModel ) {
130 if ( $currentModel['model'] === $this->model ) {
131 if ( $currentModel['mode'] ) {
132 $this->mode = $currentModel['mode'];
133 }
134 break;
135 }
136 }
137 }
138
139 /**
140 * Given a prompt, the model will return one or more predicted completions.
141 * It can also return the probabilities of alternative tokens at each position.
142 * @param string $prompt The prompt to generate completions.
143 */
144 public function setPrompt( $prompt ) {
145 parent::setPrompt( $prompt );
146 $this->validateMessages();
147 }
148
149 /**
150 * The prompt is used by models who uses Text Completion (and not Chat Completion).
151 * This returns the prompt if it's not a chat, otherwise it will build a prompt with
152 * all the messages nicely formatted.
153 */
154 public function getPrompt(): ?string {
155 if ( !$this->isChat ) {
156 return $this->prompt . $this->promptEnding;
157 }
158
159 $first = reset( $this->messages );
160 $prompt = "";
161 if ( $first && $first['role'] === 'system' ) {
162 $prompt = $first['content'] . "\n\n";
163 }
164
165 // Casually Fine-Tuned or Prompt-Ending
166 if ( !empty( $this->promptEnding ) ) {
167 $last = end( $this->messages );
168 if ( $last && $last['role'] === 'user' ) {
169 $prompt = $last['content'] . $this->promptEnding;
170 }
171 return $prompt;
172 }
173
174 // Standard Completion
175 while ( $message = next( $this->messages ) ) {
176 $role = $message['role'];
177 $content = $message['content'];
178 if ( $role === 'system' ) {
179 $prompt .= "$content\n\n";
180 }
181 if ( $role === 'user' ) {
182 $prompt .= "User: $content\n";
183 }
184 if ( $role === 'assistant' ) {
185 $prompt .= "AI: $content\n";
186 }
187 }
188 $prompt .= "AI: ";
189 return $prompt;
190 }
191
192 /**
193 * Similar to the prompt, but focus on the new/last message.
194 * Only used when the model has a chat mode (and only used in messages).
195 * @param string $prompt The messages to generate completions.
196 */
197 public function setNewMessage( string $newMessage ): void {
198 $this->newMessage = $newMessage;
199 $this->validateMessages();
200 }
201
202 public function replace( $search, $replace ) {
203 $this->prompt = str_replace( $search, $replace, $this->prompt );
204 $this->validateMessages();
205 }
206
207 public function setIsChat( $isChat ) {
208 $this->isChat = $isChat;
209 }
210
211 /**
212 * Similar to the prompt, but use an array of messages instead.
213 * @param string $prompt The messages to generate completions.
214 */
215 public function setMessages( array $messages ) {
216 $messages = array_map( function( $message ) {
217 return [ 'role' => $message['role'], 'content' => $message['content'] ];
218 }, $messages );
219 $this->messages = $messages;
220 $this->validateMessages();
221 }
222
223 public function getLastMessage(): ?string {
224 if ( !empty( $this->messages ) ) {
225 $lastMessageIndex = count( $this->messages ) - 1;
226 $lastMessage = $this->messages[$lastMessageIndex];
227 return $lastMessage['content'];
228 }
229 return null;
230 }
231
232 // Function that adds a message just before the last message
233 public function injectContext( 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->validateMessages();
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->validateMessages();
250 }
251
252 private function validateMessages(): void {
253 // Messages should end with either the prompt or, if exists, the newMessage.
254 $message = empty( $this->newMessage ) ? $this->prompt : $this->newMessage;
255 if ( empty( $this->messages ) ) {
256 $this->messages = [ [ 'role' => 'user', 'content' => $message ] ];
257 }
258 else {
259 $last = &$this->messages[ count( $this->messages ) - 1 ];
260 if ( $last['role'] === 'user' ) {
261 $last['content'] = $message;
262 }
263 else {
264 array_push( $this->messages, [ 'role' => 'user', 'content' => $message ] );
265 }
266 }
267
268 // The main context must be first.
269 if ( !empty( $this->context ) ) {
270 if ( is_array( $this->messages ) && count( $this->messages ) > 0 ) {
271 if ( $this->messages[0]['role'] !== 'system' ) {
272 array_unshift( $this->messages, [ 'role' => 'system', 'content' => $this->context ] );
273 }
274 else {
275 $this->messages[0]['content'] = $this->context;
276 }
277 }
278 }
279 }
280
281 /**
282 * The maximum number of tokens to generate in the completion.
283 * The token count of your prompt plus max_tokens cannot exceed the model's context length.
284 * Most models have a context length of 2048 tokens (except for the newest models, which support 4096).
285 * @param float $prompt The maximum number of tokens.
286 */
287 public function setMaxTokens( int $maxTokens ): void {
288 $this->maxTokens = $maxTokens;
289 }
290
291 /**
292 * Set the sampling temperature to use. Higher values means the model will take more risks.
293 * Try 0.9 for more creative applications, and 0 for ones with a well-defined reply.
294 * @param float $temperature The temperature.
295 */
296 public function setTemperature( float $temperature ): void {
297 $temperature = floatval( $temperature );
298 if ( $temperature > 1 ) {
299 $temperature = 1;
300 }
301 if ( $temperature < 0 ) {
302 $temperature = 0;
303 }
304 $this->temperature = round( $temperature, 2 );
305 }
306
307 public function setMaxSentences( int $maxSentences ): void {
308 if ( !empty( $maxSentences ) ) {
309 $this->maxSentences = intval( $maxSentences );
310 $this->validateMessages();
311 }
312 }
313
314 public function setStop( string $stop ): void {
315 $this->stop = $stop;
316 }
317
318 private function convertKeys( $params )
319 {
320 $newParams = [];
321 foreach ( $params as $key => $value ) {
322 $newKey = '';
323 $capitalizeNextChar = false;
324 for ( $i = 0; $i < strlen( $key ); $i++ ) {
325 if ( $key[$i] == '_' ) {
326 $capitalizeNextChar = true;
327 }
328 else {
329 $newKey .= $capitalizeNextChar ? strtoupper($key[$i]) : $key[$i];
330 $capitalizeNextChar = false;
331 }
332 }
333 $newParams[$newKey] = $value;
334 }
335 return $newParams;
336 }
337
338 // Based on the params of the query, update the attributes
339 public function injectParams( array $params ): void
340 {
341 // Those are for the keys passed directly by the shortcode.
342 $params = $this->convertKeys( $params );
343
344 $acceptedValues = [ true, 1, '1' ];
345 if ( !empty( $params['model'] ) ) {
346 $this->setModel( $params['model'] );
347 }
348 if ( !empty( $params['casuallyFineTuned'] ) && in_array( $params['casuallyFineTuned'], $acceptedValues, true ) ) {
349 $this->promptEnding = "\n\n###\n\n";
350 $this->stop = "\n\n";
351 $this->casuallyFineTuned = true;
352 }
353 if ( !empty( $params['prompt'] ) ) {
354 $this->setPrompt( $params['prompt'] );
355 }
356 if ( !empty( $params['context'] ) ) {
357 $this->setContext( $params['context'] );
358 }
359 if ( !empty( $params['messages'] ) ) {
360 $this->setMessages( $params['messages'] );
361 }
362 if ( !empty( $params['newMessage'] ) ) {
363 $this->setNewMessage( $params['newMessage'] );
364 }
365 if ( !empty( $params['maxTokens'] ) && intval( $params['maxTokens'] ) > 0 ) {
366 $this->setMaxTokens( intval( $params['maxTokens'] ) );
367 }
368 if ( !empty( $params['maxMessages'] ) && intval( $params['maxMessages'] ) > 0 ) {
369 $this->setMaxSentences( intval( $params['maxMessages'] ) );
370 }
371 if ( !empty( $params['maxSentences'] ) && intval( $params['maxSentences'] ) > 0 ) {
372 $this->setMaxSentences( intval( $params['maxSentences'] ) );
373 }
374 if ( !empty( $params['temperature'] ) ) {
375 $this->setTemperature( $params['temperature'] );
376 }
377 if ( !empty( $params['stop'] ) ) {
378 $this->setStop( $params['stop'] );
379 }
380 if ( !empty( $params['maxResults'] ) ) {
381 $this->setMaxResults( $params['maxResults'] );
382 }
383 if ( !empty( $params['env'] ) ) {
384 $this->setEnv( $params['env'] );
385 }
386 if ( !empty( $params['session'] ) ) {
387 $this->setSession( $params['session'] );
388 }
389 // Should add the params related to Open AI and Azure
390 if ( !empty( $params['service'] ) ) {
391 $this->setService( $params['service'] );
392 }
393 if ( !empty( $params['apiKey'] ) ) {
394 $this->setApiKey( $params['apiKey'] );
395 }
396 }
397 }