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