PluginProbe ʕ •ᴥ•ʔ
AI Engine – The Chatbot, AI Framework & MCP for WordPress / 1.6.84
AI Engine – The Chatbot, AI Framework & MCP for WordPress v1.6.84
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 / modules / chatbot.php
ai-engine / classes / modules Last commit date
assistants.php 3 years ago chatbot.php 3 years ago chatbot_legacy.php 3 years ago discussions.php 3 years ago security.php 3 years ago
chatbot.php
403 lines
1 <?php
2
3 // Params for the chatbot (front and server)
4
5 define( 'MWAI_CHATBOT_FRONT_PARAMS', [ 'aiName', 'userName', 'guestName', 'textSend', 'textClear',
6 'textInputPlaceholder', 'textInputMaxLength', 'textCompliance', 'startSentence', 'localMemory',
7 'themeId', 'window', 'icon', 'iconText', 'iconAlt', 'iconPosition', 'fullscreen', 'copyButton'
8 ] );
9 define( 'MWAI_CHATBOT_SERVER_PARAMS', [ 'id', 'env', 'mode', 'contentAware', 'embeddingsIndex', 'context',
10 'casuallyFineTuned', 'promptEnding', 'completionEnding', 'model', 'temperature', 'maxTokens',
11 'maxResults', 'apiKey', 'service'
12 ] );
13
14 // Params for the discussions (front and server)
15
16 define( 'MWAI_DISCUSSIONS_FRONT_PARAMS', [ 'themeId' ] );
17 define( 'MWAI_DISCUSSIONS_SERVER_PARAMS', [] );
18
19 class Meow_MWAI_Modules_Chatbot {
20 private $core = null;
21 private $namespace = 'mwai-ui/v1';
22 private $siteWideChatId = null;
23
24 public function __construct() {
25 global $mwai_core;
26 $this->core = $mwai_core;
27 add_shortcode( 'mwai_chatbot_v2', array( $this, 'chat_shortcode' ) );
28 add_action( 'rest_api_init', array( $this, 'rest_api_init' ) );
29 $this->siteWideChatId = $this->core->get_option( 'botId' );
30 add_action( 'wp_enqueue_scripts', array( $this, 'register_scripts' ) );
31
32 if ( $this->core->get_option( 'shortcode_chat_discussions' ) ) {
33 add_shortcode( 'mwai_discussions', [ $this, 'shortcode_chat_discussions' ] );
34 }
35 }
36
37 public function register_scripts() {
38 wp_register_script( 'mwai_highlight', MWAI_URL . 'vendor/highlightjs/highlight.min.js', [], '11.7', false );
39 $physical_file = MWAI_PATH . '/app/chatbot.js';
40 $cache_buster = file_exists( $physical_file ) ? filemtime( $physical_file ) : MWAI_VERSION;
41 wp_register_script( 'mwai_chatbot', MWAI_URL . '/app/chatbot.js', [ 'wp-element' ], $cache_buster, false );
42 if ( !empty( $this->siteWideChatId ) && $this->siteWideChatId !== 'none' ) {
43 $this->enqueue_scripts();
44 add_action( 'wp_footer', array( $this, 'inject_chat' ) );
45 }
46 }
47
48 public function enqueue_scripts() {
49 wp_enqueue_script( "mwai_chatbot" );
50 if ( $this->core->get_option( 'shortcode_chat_syntax_highlighting' ) ) {
51 wp_enqueue_script( "mwai_highlight" );
52 }
53 }
54
55 public function rest_api_init() {
56 register_rest_route( $this->namespace, '/chats/submit', array(
57 'methods' => 'POST',
58 'callback' => array( $this, 'rest_chat' ),
59 'permission_callback' => '__return_true'
60 ) );
61 }
62
63 public function basics_security_check( $id, $botId, $newMessage ) {
64 if ( empty( $newMessage ) ) {
65 error_log("AI Engine: The query was rejected - message was empty.");
66 return false;
67 }
68 if ( !$botId && !$id ) {
69 error_log("AI Engine: The query was rejected - no botId nor id was specified.");
70 return false;
71 }
72 $length = strlen( $newMessage );
73 if ( $length < 1 || $length > ( 4096 - 512 ) ) {
74 error_log("AI Engine: The query was rejected - message was too short or too long.");
75 return false;
76 }
77 return true;
78 }
79
80 public function rest_chat( $request ) {
81 try {
82 $params = $request->get_json_params();
83 $id = $params['id'] ?? null;
84 $botId = $params['botId'] ?? null;
85 $newMessage = trim( $params['newMessage'] ?? '' );
86
87 if ( !$this->basics_security_check( $id, $botId, $newMessage )) {
88 return new WP_REST_Response( [
89 'success' => false,
90 'message' => 'Sorry, your query has been rejected.' ], 403
91 );
92 }
93
94 // Custom Chatbot
95 if ( $id ) {
96 $chatbot = get_transient( 'mwai_custom_chatbot_' . $id );
97 }
98 // Registered Chatbot
99 if ( !$chatbot && $botId ) {
100 $chatbot = $this->core->getChatbot( $botId );
101 }
102
103 if ( !$chatbot ) {
104 error_log("AI Engine: No chatbot was found for this query.");
105 return new WP_REST_Response( [
106 'success' => false,
107 'message' => 'Sorry, your query has been rejected.' ], 403
108 );
109 }
110
111 // Create QueryText
112 $context = null;
113 $mode = $chatbot['mode'] ?? 'chat';
114
115 if ( $mode === 'images' ) {
116 $query = new Meow_MWAI_QueryImage( $newMessage );
117
118 // Handle Params
119 $newParams = [];
120 foreach ( $chatbot as $key => $value ) {
121 $newParams[$key] = $value;
122 }
123 foreach ( $params as $key => $value ) {
124 $newParams[$key] = $value;
125 }
126 $params = apply_filters( 'mwai_chatbot_params', $newParams );
127 $params['env'] = empty( $params['env'] ) ? 'chatbot' : $params['env'];
128 $query->injectParams( $params );
129 }
130 else {
131 $query = new Meow_MWAI_QueryText( $newMessage, 1024 );
132 $query->setIsChat( true );
133
134 // Handle Params
135 $newParams = [];
136 foreach ( $chatbot as $key => $value ) {
137 $newParams[$key] = $value;
138 }
139 foreach ( $params as $key => $value ) {
140 $newParams[$key] = $value;
141 }
142 $params = apply_filters( 'mwai_chatbot_params', $newParams );
143 $params['env'] = empty( $params['env'] ) ? 'chatbot' : $params['env'];
144 $query->injectParams( $params );
145
146 // Takeover
147 $takeoverAnswer = apply_filters( 'mwai_chatbot_takeover', null, $query, $params );
148 if ( !empty( $takeoverAnswer ) ) {
149 return new WP_REST_Response( [ 'success' => true, 'reply' => $takeoverAnswer,
150 'html' => $takeoverAnswer, 'usage' => null ], 200 );
151 }
152
153 // Moderation
154 if ( $this->core->get_option( 'shortcode_chat_moderation' ) ) {
155 global $mwai;
156 $isFlagged = $mwai->moderationCheck( $query->prompt );
157 if ( $isFlagged ) {
158 return new WP_REST_Response( [
159 'success' => false,
160 'message' => 'Sorry, your message has been rejected by moderation.' ], 403
161 );
162 }
163 }
164
165 // Awareness & Embeddings
166 $embeddingsIndex = $params['embeddingsIndex'] ?? null;
167 if ( $query->mode === 'chat' && !empty( $embeddingsIndex ) ) {
168 $context = apply_filters( 'mwai_context_search', $query, $embeddingsIndex );
169 if ( !empty( $context ) ) {
170 $content = $this->core->cleanSentences( $context['content'] );
171 $query->injectContext( $content );
172 }
173 }
174 }
175
176 // Query the AI
177 $reply = $this->core->ai->run( $query );
178 $rawText = $reply->result;
179 $extra = [];
180 if ( $context ) {
181 $extra = [ 'embeddings' => $context['embeddings'] ];
182 }
183 $html = apply_filters( 'mwai_chatbot_reply', $rawText, $query, $params, $extra );
184 if ( $this->core->get_option( 'shortcode_chat_formatting' ) ) {
185 $html = $this->core->markdown_to_html( $html );
186 }
187
188 return new WP_REST_Response( [
189 'success' => true,
190 'reply' => $rawText,
191 'images' => $reply->getType() === 'images' ? $reply->results : null,
192 'html' => $html,
193 'usage' => $reply->usage
194 ], 200 );
195 }
196 catch ( Exception $e ) {
197 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
198 return new WP_REST_Response([ 'success' => false, 'message' => $message ], 500 );
199 }
200 }
201
202 public function inject_chat() {
203 $params = $this->core->getChatbot( $this->siteWideChatId );
204 $cleanParams = [];
205 if ( !empty( $params ) ) {
206 $cleanParams['window'] = true;
207 $cleanParams['id'] = $this->siteWideChatId;
208 echo $this->chat_shortcode( $cleanParams );
209 }
210 return null;
211 }
212
213 public function build_front_params( $id, $botId ) {
214 $frontSystem = [
215 'id' => $id,
216 'botId' => $botId,
217 'userData' => $this->core->getUserData(),
218 'sessionId' => $this->core->get_session_id(),
219 'restNonce' => $this->core->get_nonce(),
220 'contextId' => get_the_ID(),
221 'pluginUrl' => MWAI_URL,
222 'restUrl' => untrailingslashit( rest_url() ),
223 'debugMode' => $this->core->get_option( 'debug_mode' ),
224 'typewriter' => $this->core->get_option( 'shortcode_chat_typewriter' ),
225 'speech_recognition' => $this->core->get_option( 'speech_recognition' ),
226 'speech_synthesis' => $this->core->get_option( 'speech_synthesis' ),
227 ];
228 return $frontSystem;
229 }
230
231 public function chat_shortcode( $atts ) {
232 $atts = empty($atts) ? [] : $atts;
233
234 // Properly handle the id, botId, and chatbot
235 // We have the same in discussions.php
236 $chatbot = null;
237 $botId = $atts['chat_id'] ?? null;
238 $id = $atts['id'] ?? null;
239 unset( $atts['chat_id'], $atts['id'] );
240 if ( $botId ) {
241 $chatbot = $this->core->getChatbot( $botId );
242 if ( !$chatbot ) {
243 return "AI Engine: Chatbot not found.";
244 }
245 }
246 if ( $id && !$chatbot ) {
247 $chatbot = $this->core->getChatbot( $id );
248 $botId = $chatbot ? $id : 'default';
249 }
250 $chatbot = $chatbot ?: $this->core->getChatbot( 'default' );
251 $botId = $botId ?: 'default';
252 $isCustom = $botId == 'default' && isset( $atts['id'] );
253
254 // Rename the keys of the atts into camelCase to match the internal params system.
255 $atts = array_map( function( $key, $value ) {
256 $key = str_replace( '_', ' ', $key );
257 $key = ucwords( $key );
258 $key = str_replace( ' ', '', $key );
259 $key = lcfirst( $key );
260 return [ $key => $value ];
261 }, array_keys( $atts ), $atts );
262 $atts = array_merge( ...$atts );
263
264 $frontParams = [];
265 foreach ( MWAI_CHATBOT_FRONT_PARAMS as $param ) {
266 if ( isset( $atts[$param] ) ) {
267 if ( $param === 'localMemory' ) {
268 $frontParams[$param] = $atts[$param] === 'true';
269 }
270 else {
271 $frontParams[$param] = $atts[$param];
272 }
273 }
274 else if ( isset( $chatbot[$param] ) ) {
275 $frontParams[$param] = $chatbot[$param];
276 }
277 }
278
279 // Server Params
280 $serverParams = [];
281 foreach ( MWAI_CHATBOT_SERVER_PARAMS as $param ) {
282 if ( isset( $atts[$param] ) ) {
283 $serverParams[$param] = $atts[$param];
284 }
285 }
286
287 // Front Params
288 $frontSystem = $this->build_front_params( $id, $botId );
289
290 // Clean Params
291 $frontParams = $this->cleanParams( $frontParams );
292 $frontSystem = $this->cleanParams( $frontSystem );
293 $serverParams = $this->cleanParams( $serverParams );
294
295 // Server-side: Keep the System Params
296 if ( count( $serverParams ) > 0 ) {
297 if ( !$isCustom ) {
298 $id = md5( json_encode( $serverParams ) );
299 $botId = null;
300 $frontSystem['id'] = $id;
301 $frontSystem['botId'] = $botId;
302 }
303 set_transient( 'mwai_custom_chatbot_' . $id, $serverParams, 60 * 60 * 24 );
304 }
305
306 // Client-side: Prepare JSON for Front Params and System Params
307 $theme = isset( $frontParams['themeId'] ) ? $this->core->getTheme( $frontParams['themeId'] ) : null;
308 $jsonFrontParams = htmlspecialchars( json_encode( $frontParams ), ENT_QUOTES, 'UTF-8' );
309 $jsonFrontSystem = htmlspecialchars( json_encode( $frontSystem ), ENT_QUOTES, 'UTF-8' );
310 $jsonFrontTheme = htmlspecialchars( json_encode( $theme ), ENT_QUOTES, 'UTF-8' );
311 //$jsonAttributes = htmlspecialchars(json_encode($atts), ENT_QUOTES, 'UTF-8');
312
313 $this->enqueue_scripts();
314 return "<div class='mwai-chatbot-container' data-params='{$jsonFrontParams}' data-system='{$jsonFrontSystem}' data-theme='{$jsonFrontTheme}'></div>";
315 }
316
317 function shortcode_chat_discussions( $atts ) {
318 $atts = empty($atts) ? [] : $atts;
319
320 // Properly handle the id, botId, and chatbot
321 // We have the same in chatbot.php
322 $chatbot = null;
323 $botId = $atts['chat_id'] ?? null;
324 $id = $atts['id'] ?? null;
325 unset( $atts['chat_id'], $atts['id'] );
326 if ( $botId ) {
327 $chatbot = $this->core->getChatbot( $botId );
328 if ( !$chatbot ) {
329 return "AI Engine: Chatbot not found.";
330 }
331 }
332 if ( $id && !$chatbot ) {
333 $chatbot = $this->core->getChatbot( $id );
334 $botId = $chatbot ? $id : 'default';
335 }
336 $chatbot = $chatbot ?: $this->core->getChatbot( 'default' );
337 $botId = $botId ?: 'default';
338 $isCustom = $botId == 'default' && isset( $atts['id'] );
339
340 // Rename the keys of the atts into camelCase to match the internal params system.
341 $atts = array_map( function( $key, $value ) {
342 $key = str_replace( '_', ' ', $key );
343 $key = ucwords( $key );
344 $key = str_replace( ' ', '', $key );
345 $key = lcfirst( $key );
346 return [ $key => $value ];
347 }, array_keys( $atts ), $atts );
348 $atts = array_merge( ...$atts );
349
350 // Front Params
351 $frontParams = [];
352 foreach ( MWAI_DISCUSSIONS_FRONT_PARAMS as $param ) {
353 if ( isset( $atts[$param] ) ) {
354 $frontParams[$param] = $atts[$param];
355 }
356 else if ( isset( $chatbot[$param] ) ) {
357 $frontParams[$param] = $chatbot[$param];
358 }
359 }
360
361 // Server Params
362 $serverParams = [];
363 foreach ( MWAI_DISCUSSIONS_SERVER_PARAMS as $param ) {
364 if ( isset( $atts[$param] ) ) {
365 $serverParams[$param] = $atts[$param];
366 }
367 }
368
369
370 // Front System
371 $frontSystem = $this->build_front_params( $id, $botId );
372
373 // Clean Params
374 $frontParams = $this->cleanParams( $frontParams );
375 $frontSystem = $this->cleanParams( $frontSystem );
376 $serverParams = $this->cleanParams( $serverParams );
377
378 $theme = isset( $frontParams['themeId'] ) ? $this->core->getTheme( $frontParams['themeId'] ) : null;
379 $jsonFrontParams = htmlspecialchars( json_encode( $frontParams ), ENT_QUOTES, 'UTF-8' );
380 $jsonFrontSystem = htmlspecialchars( json_encode( $frontSystem ), ENT_QUOTES, 'UTF-8' );
381 $jsonFrontTheme = htmlspecialchars( json_encode( $theme ), ENT_QUOTES, 'UTF-8' );
382
383 return "<div class='mwai-discussions-container' data-params='{$jsonFrontParams}' data-system='{$jsonFrontSystem}' data-theme='{$jsonFrontTheme}'></div>";
384 }
385
386 function cleanParams( &$params ) {
387 foreach ( $params as $param => $value ) {
388 if ( empty( $value ) || is_array( $value ) ) {
389 continue;
390 }
391 $lowerCaseValue = strtolower( $value );
392 if ( $lowerCaseValue === 'true' || $lowerCaseValue === 'false' || is_bool( $value ) ) {
393 $params[$param] = filter_var( $value, FILTER_VALIDATE_BOOLEAN );
394 }
395 else if ( is_numeric( $value ) ) {
396 $params[$param] = filter_var( $value, FILTER_VALIDATE_FLOAT );
397 }
398 }
399 return $params;
400 }
401
402 }
403