PluginProbe ʕ •ᴥ•ʔ
AI Engine – The Chatbot, AI Framework & MCP for WordPress / 1.6.82
AI Engine – The Chatbot, AI Framework & MCP for WordPress v1.6.82
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 / 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
402 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 return new WP_REST_Response( [ 'success' => false, 'message' => $e->getMessage() ], 500 );
198 }
199 }
200
201 public function inject_chat() {
202 $params = $this->core->getChatbot( $this->siteWideChatId );
203 $cleanParams = [];
204 if ( !empty( $params ) ) {
205 $cleanParams['window'] = true;
206 $cleanParams['id'] = $this->siteWideChatId;
207 echo $this->chat_shortcode( $cleanParams );
208 }
209 return null;
210 }
211
212 public function build_front_params( $id, $botId ) {
213 $frontSystem = [
214 'id' => $id,
215 'botId' => $botId,
216 'userData' => $this->core->getUserData(),
217 'sessionId' => $this->core->get_session_id(),
218 'restNonce' => $this->core->get_nonce(),
219 'contextId' => get_the_ID(),
220 'pluginUrl' => MWAI_URL,
221 'restUrl' => untrailingslashit( rest_url() ),
222 'debugMode' => $this->core->get_option( 'debug_mode' ),
223 'typewriter' => $this->core->get_option( 'shortcode_chat_typewriter' ),
224 'speech_recognition' => $this->core->get_option( 'speech_recognition' ),
225 'speech_synthesis' => $this->core->get_option( 'speech_synthesis' ),
226 ];
227 return $frontSystem;
228 }
229
230 public function chat_shortcode( $atts ) {
231 $atts = empty($atts) ? [] : $atts;
232
233 // Properly handle the id, botId, and chatbot
234 // We have the same in discussions.php
235 $chatbot = null;
236 $botId = $atts['chat_id'] ?? null;
237 $id = $atts['id'] ?? null;
238 unset( $atts['chat_id'], $atts['id'] );
239 if ( $botId ) {
240 $chatbot = $this->core->getChatbot( $botId );
241 if ( !$chatbot ) {
242 return "AI Engine: Chatbot not found.";
243 }
244 }
245 if ( $id && !$chatbot ) {
246 $chatbot = $this->core->getChatbot( $id );
247 $botId = $chatbot ? $id : 'default';
248 }
249 $chatbot = $chatbot ?: $this->core->getChatbot( 'default' );
250 $botId = $botId ?: 'default';
251 $isCustom = $botId == 'default' && isset( $atts['id'] );
252
253 // Rename the keys of the atts into camelCase to match the internal params system.
254 $atts = array_map( function( $key, $value ) {
255 $key = str_replace( '_', ' ', $key );
256 $key = ucwords( $key );
257 $key = str_replace( ' ', '', $key );
258 $key = lcfirst( $key );
259 return [ $key => $value ];
260 }, array_keys( $atts ), $atts );
261 $atts = array_merge( ...$atts );
262
263 $frontParams = [];
264 foreach ( MWAI_CHATBOT_FRONT_PARAMS as $param ) {
265 if ( isset( $atts[$param] ) ) {
266 if ( $param === 'localMemory' ) {
267 $frontParams[$param] = $atts[$param] === 'true';
268 }
269 else {
270 $frontParams[$param] = $atts[$param];
271 }
272 }
273 else if ( isset( $chatbot[$param] ) ) {
274 $frontParams[$param] = $chatbot[$param];
275 }
276 }
277
278 // Server Params
279 $serverParams = [];
280 foreach ( MWAI_CHATBOT_SERVER_PARAMS as $param ) {
281 if ( isset( $atts[$param] ) ) {
282 $serverParams[$param] = $atts[$param];
283 }
284 }
285
286 // Front Params
287 $frontSystem = $this->build_front_params( $id, $botId );
288
289 // Clean Params
290 $frontParams = $this->cleanParams( $frontParams );
291 $frontSystem = $this->cleanParams( $frontSystem );
292 $serverParams = $this->cleanParams( $serverParams );
293
294 // Server-side: Keep the System Params
295 if ( count( $serverParams ) > 0 ) {
296 if ( !$isCustom ) {
297 $id = md5( json_encode( $serverParams ) );
298 $botId = null;
299 $frontSystem['id'] = $id;
300 $frontSystem['botId'] = $botId;
301 }
302 set_transient( 'mwai_custom_chatbot_' . $id, $serverParams, 60 * 60 * 24 );
303 }
304
305 // Client-side: Prepare JSON for Front Params and System Params
306 $theme = isset( $frontParams['themeId'] ) ? $this->core->getTheme( $frontParams['themeId'] ) : null;
307 $jsonFrontParams = htmlspecialchars( json_encode( $frontParams ), ENT_QUOTES, 'UTF-8' );
308 $jsonFrontSystem = htmlspecialchars( json_encode( $frontSystem ), ENT_QUOTES, 'UTF-8' );
309 $jsonFrontTheme = htmlspecialchars( json_encode( $theme ), ENT_QUOTES, 'UTF-8' );
310 //$jsonAttributes = htmlspecialchars(json_encode($atts), ENT_QUOTES, 'UTF-8');
311
312 $this->enqueue_scripts();
313 return "<div class='mwai-chatbot-container' data-params='{$jsonFrontParams}' data-system='{$jsonFrontSystem}' data-theme='{$jsonFrontTheme}'></div>";
314 }
315
316 function shortcode_chat_discussions( $atts ) {
317 $atts = empty($atts) ? [] : $atts;
318
319 // Properly handle the id, botId, and chatbot
320 // We have the same in chatbot.php
321 $chatbot = null;
322 $botId = $atts['chat_id'] ?? null;
323 $id = $atts['id'] ?? null;
324 unset( $atts['chat_id'], $atts['id'] );
325 if ( $botId ) {
326 $chatbot = $this->core->getChatbot( $botId );
327 if ( !$chatbot ) {
328 return "AI Engine: Chatbot not found.";
329 }
330 }
331 if ( $id && !$chatbot ) {
332 $chatbot = $this->core->getChatbot( $id );
333 $botId = $chatbot ? $id : 'default';
334 }
335 $chatbot = $chatbot ?: $this->core->getChatbot( 'default' );
336 $botId = $botId ?: 'default';
337 $isCustom = $botId == 'default' && isset( $atts['id'] );
338
339 // Rename the keys of the atts into camelCase to match the internal params system.
340 $atts = array_map( function( $key, $value ) {
341 $key = str_replace( '_', ' ', $key );
342 $key = ucwords( $key );
343 $key = str_replace( ' ', '', $key );
344 $key = lcfirst( $key );
345 return [ $key => $value ];
346 }, array_keys( $atts ), $atts );
347 $atts = array_merge( ...$atts );
348
349 // Front Params
350 $frontParams = [];
351 foreach ( MWAI_DISCUSSIONS_FRONT_PARAMS as $param ) {
352 if ( isset( $atts[$param] ) ) {
353 $frontParams[$param] = $atts[$param];
354 }
355 else if ( isset( $chatbot[$param] ) ) {
356 $frontParams[$param] = $chatbot[$param];
357 }
358 }
359
360 // Server Params
361 $serverParams = [];
362 foreach ( MWAI_DISCUSSIONS_SERVER_PARAMS as $param ) {
363 if ( isset( $atts[$param] ) ) {
364 $serverParams[$param] = $atts[$param];
365 }
366 }
367
368
369 // Front System
370 $frontSystem = $this->build_front_params( $id, $botId );
371
372 // Clean Params
373 $frontParams = $this->cleanParams( $frontParams );
374 $frontSystem = $this->cleanParams( $frontSystem );
375 $serverParams = $this->cleanParams( $serverParams );
376
377 $theme = isset( $frontParams['themeId'] ) ? $this->core->getTheme( $frontParams['themeId'] ) : null;
378 $jsonFrontParams = htmlspecialchars( json_encode( $frontParams ), ENT_QUOTES, 'UTF-8' );
379 $jsonFrontSystem = htmlspecialchars( json_encode( $frontSystem ), ENT_QUOTES, 'UTF-8' );
380 $jsonFrontTheme = htmlspecialchars( json_encode( $theme ), ENT_QUOTES, 'UTF-8' );
381
382 return "<div class='mwai-discussions-container' data-params='{$jsonFrontParams}' data-system='{$jsonFrontSystem}' data-theme='{$jsonFrontTheme}'></div>";
383 }
384
385 function cleanParams( &$params ) {
386 foreach ( $params as $param => $value ) {
387 if ( empty( $value ) || is_array( $value ) ) {
388 continue;
389 }
390 $lowerCaseValue = strtolower( $value );
391 if ( $lowerCaseValue === 'true' || $lowerCaseValue === 'false' || is_bool( $value ) ) {
392 $params[$param] = filter_var( $value, FILTER_VALIDATE_BOOLEAN );
393 }
394 else if ( is_numeric( $value ) ) {
395 $params[$param] = filter_var( $value, FILTER_VALIDATE_FLOAT );
396 }
397 }
398 return $params;
399 }
400
401 }
402