PluginProbe ʕ •ᴥ•ʔ
AI Engine – The Chatbot, AI Framework & MCP for WordPress / 1.9.92
AI Engine – The Chatbot, AI Framework & MCP for WordPress v1.9.92
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 2 years ago chatbot_legacy.php 2 years ago discussions.php 2 years ago security.php 3 years ago
chatbot.php
501 lines
1 <?php
2
3 // Params for the chatbot (front and server)
4
5 define( 'MWAI_CHATBOT_FRONT_PARAMS', [ 'id', 'customId', 'aiName', 'userName', 'guestName',
6 'textSend', 'textClear',
7 'textInputPlaceholder', 'textInputMaxLength', 'textCompliance', 'startSentence', 'localMemory',
8 'themeId', 'window', 'icon', 'iconText', 'iconAlt', 'iconPosition', 'fullscreen', 'copyButton'
9 ] );
10 define( 'MWAI_CHATBOT_SERVER_PARAMS', [ 'id', 'envId', 'env', 'mode', 'contentAware', 'context',
11 'embeddingsEnvId', 'embeddingsIndex', 'embeddingsNamespace',
12 'casuallyFineTuned', 'promptEnding', 'completionEnding', 'model', 'temperature', 'maxTokens',
13 'maxResults', 'apiKey', 'service'
14 ] );
15
16 // Params for the discussions (front and server)
17
18 define( 'MWAI_DISCUSSIONS_FRONT_PARAMS', [ 'themeId', 'textNewChat' ] );
19 define( 'MWAI_DISCUSSIONS_SERVER_PARAMS', [ 'customId' ] );
20
21 class Meow_MWAI_Modules_Chatbot {
22 private $core = null;
23 private $namespace = 'mwai-ui/v1';
24 private $siteWideChatId = null;
25
26 public function __construct() {
27 global $mwai_core;
28 $this->core = $mwai_core;
29 add_shortcode( 'mwai_chatbot_v2', array( $this, 'chat_shortcode' ) );
30 add_action( 'rest_api_init', array( $this, 'rest_api_init' ) );
31 $this->siteWideChatId = $this->core->get_option( 'botId' );
32 add_action( 'wp_enqueue_scripts', array( $this, 'register_scripts' ) );
33
34 if ( $this->core->get_option( 'shortcode_chat_discussions' ) ) {
35 add_shortcode( 'mwai_discussions', [ $this, 'shortcode_chat_discussions' ] );
36 }
37 }
38
39 public function register_scripts() {
40 $physical_file = trailingslashit( MWAI_PATH ) . 'app/chatbot.js';
41 $cache_buster = file_exists( $physical_file ) ? filemtime( $physical_file ) : MWAI_VERSION;
42 wp_register_script( 'mwai_chatbot', trailingslashit( MWAI_URL ) . 'app/chatbot.js',
43 [ 'wp-element' ], $cache_buster, false );
44 if ( !empty( $this->siteWideChatId ) && $this->siteWideChatId !== 'none' ) {
45 $this->enqueue_scripts();
46 add_action( 'wp_footer', array( $this, 'inject_chat' ) );
47 }
48 }
49
50 public function enqueue_scripts() {
51 wp_enqueue_script( "mwai_chatbot" );
52 if ( $this->core->get_option( 'shortcode_chat_syntax_highlighting' ) ) {
53 wp_enqueue_script( "mwai_highlight" );
54 }
55 }
56
57 public function rest_api_init() {
58 register_rest_route( $this->namespace, '/chats/submit', array(
59 'methods' => 'POST',
60 'callback' => array( $this, 'rest_chat' ),
61 'permission_callback' => '__return_true'
62 ) );
63
64 }
65
66 public function basics_security_check( $botId, $customId, $newMessage ) {
67 if ( empty( $newMessage ) ) {
68 error_log("AI Engine: The query was rejected - message was empty.");
69 return false;
70 }
71 if ( !$botId && !$customId ) {
72 error_log("AI Engine: The query was rejected - no botId nor id was specified.");
73 return false;
74 }
75
76 $length = strlen( $newMessage );
77 if ( $length < 1 || $length > ( 4096 * 16 ) ) {
78 error_log("AI Engine: The query was rejected - message was too short or too long.");
79 return false;
80 }
81 return true;
82 }
83
84 public function rest_chat( $request ) {
85 $params = $request->get_json_params();
86 $botId = $params['botId'] ?? null;
87 $customId = $params['customId'] ?? null;
88 $stream = $params['stream'] ?? false;
89 $newMessage = trim( $params['newMessage'] ?? '' );
90
91 if ( !$this->basics_security_check( $botId, $customId, $newMessage )) {
92 return new WP_REST_Response( [
93 'success' => false,
94 'message' => apply_filters( 'mwai_ai_exception', 'Sorry, your query has been rejected.' )
95 ], 403 );
96 }
97
98 try {
99 $data = $this->chat_submit( $botId, $newMessage, $params, $stream );
100 return new WP_REST_Response( [
101 'success' => true,
102 'reply' => $data['reply'],
103 'images' => $data['images'],
104 'usage' => $data['usage']
105 ], 200 );
106 }
107 catch ( Exception $e ) {
108 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
109 return new WP_REST_Response( [
110 'success' => false,
111 'message' => $message
112 ], 500 );
113 }
114 }
115
116 public function chat_submit( $botId, $newMessage, $params = [], $stream = false ) {
117 try {
118 $chatbot = null;
119 $customId = $params['customId'] ?? null;
120
121 // Custom Chatbot
122 if ( $customId ) {
123 $chatbot = get_transient( 'mwai_custom_chatbot_' . $customId );
124 }
125 // Registered Chatbot
126 if ( !$chatbot && $botId ) {
127 $chatbot = $this->core->getChatbot( $botId );
128 }
129
130 if ( !$chatbot ) {
131 error_log("AI Engine: No chatbot was found for this query.");
132 throw new Exception( 'Sorry, your query has been rejected.' );
133 }
134
135 // Create QueryText
136 $context = null;
137 $mode = $chatbot['mode'] ?? 'chat';
138
139 if ( $mode === 'images' ) {
140 $query = new Meow_MWAI_Query_Image( $newMessage );
141
142 // Handle Params
143 $newParams = [];
144 foreach ( $chatbot as $key => $value ) {
145 $newParams[$key] = $value;
146 }
147 foreach ( $params as $key => $value ) {
148 $newParams[$key] = $value;
149 }
150 $params = apply_filters( 'mwai_chatbot_params', $newParams );
151 $params['env'] = empty( $params['env'] ) ? 'chatbot' : $params['env'];
152 $query->injectParams( $params );
153 }
154 else {
155 $query = new Meow_MWAI_Query_Text( $newMessage, 1024 );
156 $streamCallback = null;
157
158 // Handle Params
159 $newParams = [];
160 foreach ( $chatbot as $key => $value ) {
161 $newParams[$key] = $value;
162 }
163 foreach ( $params as $key => $value ) {
164 $newParams[$key] = $value;
165 }
166 $params = apply_filters( 'mwai_chatbot_params', $newParams );
167 $params['env'] = empty( $params['env'] ) ? 'chatbot' : $params['env'];
168 $query->injectParams( $params );
169
170 // Takeover
171 $takeoverAnswer = apply_filters( 'mwai_chatbot_takeover', null, $query, $params );
172 if ( !empty( $takeoverAnswer ) ) {
173 return [
174 'reply' => $takeoverAnswer,
175 'images' => null,
176 'usage' => null
177 ];
178 }
179
180 // Moderation
181 if ( $this->core->get_option( 'shortcode_chat_moderation' ) ) {
182 global $mwai;
183 $isFlagged = $mwai->moderationCheck( $query->prompt );
184 if ( $isFlagged ) {
185 throw new Exception( 'Sorry, your message has been rejected by moderation.' );
186 }
187 }
188
189 // Awareness & Embeddings
190 // TODO: This is same in Chatbot Legacy and Forms, maybe we should move it to the core?
191 $embeddingsEnvId = $params['embeddingsEnvId'] ?? null;
192 $embeddingsIndex = $params['embeddingsIndex'] ?? null;
193 $embeddingsNamespace = $params['embeddingsNamespace'] ?? null;
194 if ( $query->mode === 'chat' ) {
195 $context = apply_filters( 'mwai_context_search', $context, $query, [
196 'embeddingsEnvId' => $embeddingsEnvId,
197 'embeddingsIndex' => $embeddingsIndex,
198 'embeddingsNamespace' => $embeddingsNamespace
199 ] );
200 if ( !empty( $context ) ) {
201 if ( isset( $context['content'] ) ) {
202 $content = $this->core->cleanSentences( $context['content'] );
203 $query->injectContext( $content );
204 }
205 else {
206 error_log( "AI Engine: A context without content was returned." );
207 }
208 }
209 }
210 }
211
212 // Process Query
213 if ( $stream ) {
214 $streamCallback = function( $reply ) {
215 //$raw = _wp_specialchars( $reply, ENT_NOQUOTES, 'UTF-8', true );
216 $raw = $reply;
217 $this->stream_push( [ 'type' => 'live', 'data' => $raw ] );
218 if ( ob_get_level() > 0 ) {
219 ob_flush();
220 }
221 flush();
222 };
223 header( 'Cache-Control: no-cache' );
224 header( 'Content-Type: text/event-stream' );
225 header( 'X-Accel-Buffering: no' ); // This is useful to disable buffering in nginx through headers.
226 ob_implicit_flush( true );
227 ob_end_flush();
228 }
229
230 $reply = $this->core->ai->run( $query, $streamCallback );
231 $rawText = $reply->result;
232 $extra = [];
233 if ( $context ) {
234 $extra = [ 'embeddings' => $context['embeddings'] ];
235 }
236
237 $rawText = apply_filters( 'mwai_chatbot_reply', $rawText, $query, $params, $extra );
238 // TODO: There is no need for the shortcode_chat_formatting sice Markdown is handled on the client side.
239 // if ( $this->core->get_option( 'shortcode_chat_formatting' ) ) {
240 // $html = $this->core->markdown_to_html( $rawText );
241 // }
242
243 $restRes = [
244 'reply' => $rawText,
245 'images' => $reply->getType() === 'images' ? $reply->results : null,
246 'usage' => $reply->usage
247 ];
248
249 // Process Reply
250 if ( $stream ) {
251 $this->stream_push( [
252 'type' => 'end',
253 'data' => json_encode([
254 'success' => true,
255 'reply' => $restRes['reply'],
256 'images' => $restRes['images'],
257 'usage' => $restRes['usage']
258 ])
259 ] );
260 die();
261 }
262 else {
263 return $restRes;
264 }
265
266 }
267 catch ( Exception $e ) {
268 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
269 if ( $stream ) {
270 $this->stream_push( [ 'type' => 'error', 'data' => $message ] );
271 die();
272 }
273 else {
274 throw $e;
275 }
276 }
277 }
278
279 public function stream_push( $data ) {
280 $out = "data: " . json_encode( $data );
281 echo $out;
282 echo "\n\n";
283 if (ob_get_level() > 0) {
284 ob_end_flush();
285 }
286 flush();
287 }
288
289 public function inject_chat() {
290 $params = $this->core->getChatbot( $this->siteWideChatId );
291 $cleanParams = [];
292 if ( !empty( $params ) ) {
293 $cleanParams['window'] = true;
294 $cleanParams['id'] = $this->siteWideChatId;
295 echo $this->chat_shortcode( $cleanParams );
296 }
297 return null;
298 }
299
300 public function build_front_params( $botId, $customId ) {
301 $frontSystem = [
302 'botId' => $customId ? null : $botId,
303 'customId' => $customId,
304 'userData' => $this->core->getUserData(),
305 'sessionId' => $this->core->get_session_id(),
306 'restNonce' => $this->core->get_nonce(),
307 'contextId' => get_the_ID(),
308 'pluginUrl' => MWAI_URL,
309 'restUrl' => untrailingslashit( rest_url() ),
310 'debugMode' => $this->core->get_option( 'debug_mode' ),
311 'typewriter' => $this->core->get_option( 'shortcode_chat_typewriter' ),
312 'speech_recognition' => $this->core->get_option( 'speech_recognition' ),
313 'speech_synthesis' => $this->core->get_option( 'speech_synthesis' ),
314 'stream' => $this->core->get_option( 'shortcode_chat_stream' ),
315 ];
316 return $frontSystem;
317 }
318
319 public function resolveBotInfo( &$atts )
320 {
321 $chatbot = null;
322 $botId = $atts['id'] ?? null;
323 $customId = $atts['custom_id'] ?? null;
324 if (!$botId && !$customId) {
325 $botId = "default";
326 }
327 if ( $botId ) {
328 $chatbot = $this->core->getChatbot( $botId );
329 if (!$chatbot) {
330 $botId = $botId ?: 'N/A';
331 return [
332 'error' => "AI Engine: Chatbot '{$botId}' not found. If you meant to set an ID for your custom chatbot, please use 'custom_id' instead of 'id'.",
333 ];
334 }
335 }
336 $chatbot = $chatbot ?: $this->core->getChatbot( 'default' );
337 if ( !empty( $customId ) ) {
338 $botId = null;
339 }
340 unset( $atts['id'] );
341 return [
342 'chatbot' => $chatbot,
343 'botId' => $botId,
344 'customId' => $customId,
345 ];
346 }
347
348 public function chat_shortcode( $atts ) {
349 $atts = empty($atts) ? [] : $atts;
350
351 // Let the user override the chatbot params
352 $atts = apply_filters( 'mwai_chatbot_params', $atts );
353
354 // Resolve the bot info
355 $resolvedBot = $this->resolveBotInfo( $atts, 'chatbot' );
356 if ( isset( $resolvedBot['error'] ) ) {
357 return $resolvedBot['error'];
358 }
359 $chatbot = $resolvedBot['chatbot'];
360 $botId = $resolvedBot['botId'];
361 $customId = $resolvedBot['customId'];
362
363 // Rename the keys of the atts into camelCase to match the internal params system.
364 $atts = array_map( function( $key, $value ) {
365 $key = str_replace( '_', ' ', $key );
366 $key = ucwords( $key );
367 $key = str_replace( ' ', '', $key );
368 $key = lcfirst( $key );
369 return [ $key => $value ];
370 }, array_keys( $atts ), $atts );
371 $atts = array_merge( ...$atts );
372
373 $frontParams = [];
374 foreach ( MWAI_CHATBOT_FRONT_PARAMS as $param ) {
375 if ( isset( $atts[$param] ) ) {
376 if ( $param === 'localMemory' ) {
377 $frontParams[$param] = $atts[$param] === 'true';
378 }
379 else {
380 $frontParams[$param] = $atts[$param];
381 }
382 }
383 else if ( isset( $chatbot[$param] ) ) {
384 $frontParams[$param] = $chatbot[$param];
385 }
386 }
387
388 // Server Params
389 $serverParams = [];
390 foreach ( MWAI_CHATBOT_SERVER_PARAMS as $param ) {
391 if ( isset( $atts[$param] ) ) {
392 $serverParams[$param] = $atts[$param];
393 }
394 else {
395 $serverParams[$param] = $chatbot[$param] ?? null;
396 }
397 }
398
399 // Front Params
400 $frontSystem = $this->build_front_params( $botId, $customId );
401
402 // Clean Params
403 $frontParams = $this->cleanParams( $frontParams );
404 $frontSystem = $this->cleanParams( $frontSystem );
405 $serverParams = $this->cleanParams( $serverParams );
406
407 // Server-side: Keep the System Params
408 if ( count( $serverParams ) > 0 ) {
409 if ( empty( $customId ) ) {
410 $customId = md5( json_encode( $serverParams ) );
411 $frontSystem['customId'] = $customId;
412 }
413 set_transient( 'mwai_custom_chatbot_' . $customId, $serverParams, 60 * 60 * 24 );
414 }
415
416 // Client-side: Prepare JSON for Front Params and System Params
417 $theme = isset( $frontParams['themeId'] ) ? $this->core->getTheme( $frontParams['themeId'] ) : null;
418 $jsonFrontParams = htmlspecialchars( json_encode( $frontParams ), ENT_QUOTES, 'UTF-8' );
419 $jsonFrontSystem = htmlspecialchars( json_encode( $frontSystem ), ENT_QUOTES, 'UTF-8' );
420 $jsonFrontTheme = htmlspecialchars( json_encode( $theme ), ENT_QUOTES, 'UTF-8' );
421 //$jsonAttributes = htmlspecialchars(json_encode($atts), ENT_QUOTES, 'UTF-8');
422
423 $this->enqueue_scripts();
424 return "<div class='mwai-chatbot-container' data-params='{$jsonFrontParams}' data-system='{$jsonFrontSystem}' data-theme='{$jsonFrontTheme}'></div>";
425 }
426
427 function shortcode_chat_discussions( $atts ) {
428 $atts = empty($atts) ? [] : $atts;
429
430 // Resolve the bot info
431 $resolvedBot = $this->resolveBotInfo( $atts );
432 if ( isset( $resolvedBot['error'] ) ) {
433 return $resolvedBot['error'];
434 }
435 $chatbot = $resolvedBot['chatbot'];
436 $botId = $resolvedBot['botId'];
437 $customId = $resolvedBot['customId'];
438
439 // Rename the keys of the atts into camelCase to match the internal params system.
440 $atts = array_map( function( $key, $value ) {
441 $key = str_replace( '_', ' ', $key );
442 $key = ucwords( $key );
443 $key = str_replace( ' ', '', $key );
444 $key = lcfirst( $key );
445 return [ $key => $value ];
446 }, array_keys( $atts ), $atts );
447 $atts = array_merge( ...$atts );
448
449 // Front Params
450 $frontParams = [];
451 foreach ( MWAI_DISCUSSIONS_FRONT_PARAMS as $param ) {
452 if ( isset( $atts[$param] ) ) {
453 $frontParams[$param] = $atts[$param];
454 }
455 else if ( isset( $chatbot[$param] ) ) {
456 $frontParams[$param] = $chatbot[$param];
457 }
458 }
459
460 // Server Params
461 $serverParams = [];
462 foreach ( MWAI_DISCUSSIONS_SERVER_PARAMS as $param ) {
463 if ( isset( $atts[$param] ) ) {
464 $serverParams[$param] = $atts[$param];
465 }
466 }
467
468 // Front System
469 $frontSystem = $this->build_front_params( $botId, $customId );
470
471 // Clean Params
472 $frontParams = $this->cleanParams( $frontParams );
473 $frontSystem = $this->cleanParams( $frontSystem );
474 $serverParams = $this->cleanParams( $serverParams );
475
476 $theme = isset( $frontParams['themeId'] ) ? $this->core->getTheme( $frontParams['themeId'] ) : null;
477 $jsonFrontParams = htmlspecialchars( json_encode( $frontParams ), ENT_QUOTES, 'UTF-8' );
478 $jsonFrontSystem = htmlspecialchars( json_encode( $frontSystem ), ENT_QUOTES, 'UTF-8' );
479 $jsonFrontTheme = htmlspecialchars( json_encode( $theme ), ENT_QUOTES, 'UTF-8' );
480
481 return "<div class='mwai-discussions-container' data-params='{$jsonFrontParams}' data-system='{$jsonFrontSystem}' data-theme='{$jsonFrontTheme}'></div>";
482 }
483
484 function cleanParams( &$params ) {
485 foreach ( $params as $param => $value ) {
486 if ( empty( $value ) || is_array( $value ) ) {
487 continue;
488 }
489 $lowerCaseValue = strtolower( $value );
490 if ( $lowerCaseValue === 'true' || $lowerCaseValue === 'false' || is_bool( $value ) ) {
491 $params[$param] = filter_var( $value, FILTER_VALIDATE_BOOLEAN );
492 }
493 else if ( is_numeric( $value ) ) {
494 $params[$param] = filter_var( $value, FILTER_VALIDATE_FLOAT );
495 }
496 }
497 return $params;
498 }
499
500 }
501