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