PluginProbe ʕ •ᴥ•ʔ
AI Engine – The Chatbot, AI Framework & MCP for WordPress / 1.4.4
AI Engine – The Chatbot, AI Framework & MCP for WordPress v1.4.4
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_legacy.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
chatbot_legacy.php
843 lines
1 <?php
2
3 class Meow_MWAI_Modules_Chatbot_Legacy {
4 private $core = null;
5 private $namespace = 'ai-chatbot/v1';
6 private $usingChat = false;
7
8 public function __construct() {
9 global $mwai_core;
10 $this->core = $mwai_core;
11 if ( is_admin() ) { return; }
12 add_shortcode( 'mwai_chat', array( $this, 'chat' ) );
13 add_shortcode( 'mwai_chatbot', array( $this, 'chat' ) );
14 add_shortcode( 'mwai_imagesbot', array( $this, 'imageschat' ) );
15 add_action( 'rest_api_init', array( $this, 'rest_api_init' ) );
16 add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
17
18 if ( $this->core->get_option( 'shortcode_chat_inject' ) ) {
19 add_action( 'wp_footer', array( $this, 'inject_chat' ) );
20 }
21
22 if ( $this->core->get_option( 'shortcode_chat_styles' ) ) {
23 add_filter( 'mwai_chatbot_style', [ $this, 'apply_chat_styles' ], 10, 2 );
24 }
25 }
26
27 public function enqueue_scripts() {
28 if ( $this->core->get_option( 'shortcode_chat_syntax_highlighting' ) ) {
29 wp_enqueue_script( 'mwai_chatbot', MWAI_URL . 'vendor/highlightjs/highlight.min.js', [], '11.7', false );
30 wp_enqueue_style( 'mwai_chatbot', MWAI_URL . '/vendor/highlightjs/stackoverflow-dark.min.css', [], '11.7' );
31 }
32 if ( $this->core->get_option( 'shortcode_chat_typewriter' ) ) {
33 wp_enqueue_script( 'mwai_chatbot_typewriter', MWAI_URL . 'vendor/typewriterjs/typewriter.min.js', [], '2.0', true );
34 }
35 }
36
37 public function rest_api_init() {
38 register_rest_route( $this->namespace, '/chat', array(
39 'methods' => 'POST',
40 'callback' => array( $this, 'rest_chat' ),
41 'permission_callback' => '__return_true'
42 ) );
43 register_rest_route( $this->namespace, '/imagesbot', array(
44 'methods' => 'POST',
45 'callback' => array( $this, 'rest_imagesbot' ),
46 'permission_callback' => '__return_true'
47 ) );
48 }
49
50 public function chatgpt_style( $id ) {
51 $css = file_get_contents( MWAI_PATH . '/themes/ChatGPT.module.css' );
52 $css = str_replace( '#mwai-chat-id', "#mwai-chat-{$id}", $css );
53 return '<style>' . $css . '</style>';
54 }
55
56 public function basics_security_check( $params ) {
57 if ( empty( $params['newMessage'] ) ) {
58 return false;
59 }
60 $length = strlen( trim( $params['newMessage'] ) );
61 if ( $length < 1 || $length > ( 4096 - 512 ) ) {
62 return false;
63 }
64 if ( empty( $params['prompt'] ) ) {
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 $query = new Meow_MWAI_QueryText( $params['newMessage'], 1024 );
81 //$query->setIsChat( true );
82 $query->injectParams( $params );
83
84 $takeoverAnswer = apply_filters( 'mwai_chatbot_takeover', null, $query, $params );
85 if ( !empty( $takeoverAnswer ) ) {
86 return new WP_REST_Response( [ 'success' => true, 'answer' => $takeoverAnswer,
87 'html' => $takeoverAnswer, 'usage' => null ], 200 );
88 }
89
90 // Moderation
91 if ( $this->core->get_option( 'shortcode_chat_moderation' ) ) {
92 global $mwai;
93 $isFlagged = $mwai->moderationCheck( $query->prompt );
94 if ( $isFlagged ) {
95 return new WP_REST_Response( [
96 'success' => false,
97 'message' => 'Sorry, your message has been rejected by moderation.' ], 403
98 );
99 }
100 }
101
102 // Awareness & Embeddings
103 $context = null;
104 $embeddingsIndex = $params['embeddingsIndex'];
105 if ( $query->mode === 'chat' && !empty( $embeddingsIndex ) ) {
106 $context = apply_filters( 'mwai_context_search', $query, $embeddingsIndex );
107 if ( !empty( $context ) ) {
108 $query->injectContext( $context['content'] );
109 }
110 }
111
112 $answer = $this->core->ai->run( $query );
113 $rawText = $answer->result;
114 $extra = [];
115 if ( $context ) {
116 $extra = [ 'embeddings' => $context['embeddings'] ];
117 }
118 $html = apply_filters( 'mwai_chatbot_reply', $rawText, $query, $params, $extra );
119 if ( $this->core->get_option( 'shortcode_chat_formatting' ) ) {
120 $html = $this->core->markdown_to_html( $html );
121 }
122 return new WP_REST_Response( [ 'success' => true, 'answer' => $rawText,
123 'html' => $html, 'usage' => $answer->usage ], 200 );
124 }
125 catch ( Exception $e ) {
126 return new WP_REST_Response( [ 'success' => false, 'message' => $e->getMessage() ], 500 );
127 }
128 }
129
130 public function rest_imagesbot( $request ) {
131 try {
132 $params = $request->get_json_params();
133 $query = new Meow_MWAI_QueryImage( $params['prompt'] );
134 $query->injectParams( $params );
135 $answer = $this->core->ai->run( $query );
136 return new WP_REST_Response( [ 'success' => true, 'images' => $answer->results, 'usage' => $answer->usage ], 200 );
137 }
138 catch ( Exception $e ) {
139 return new WP_REST_Response( [ 'success' => false, 'message' => $e->getMessage() ], 500 );
140 }
141 }
142
143 public function apply_chat_styles( $css, $chatbotId ) {
144 $chatStyles = $this->core->get_option( 'shortcode_chat_styles' );
145 return preg_replace_callback( '/--mwai-(\w+):\s*([^;]+);/', function ( $matches ) use ( $chatStyles ) {
146 if ( isset( $chatStyles[$matches[1]] ) ) {
147 return '--mwai-' . $matches[1] . ': ' . $chatStyles[$matches[1]] . ';';
148 }
149 return $matches[0];
150 }, $css );
151 }
152
153 public function inject_chat() {
154 $params = $this->core->get_option( 'shortcode_chat_params' );
155 echo $this->chat( $params );
156 }
157
158 public function imageschat( $atts ) {
159 $atts['mode'] = 'images';
160 return $this->chat( $atts );
161 }
162
163 public function getCurrentUser() {
164 if ( is_user_logged_in() ) {
165 return wp_get_current_user();
166 }
167 return null;
168 }
169
170 public function handlePlaceholders( $data, $guestName = 'Guest: ' ) {
171 if ( strpos( $data, '{' ) === false ) {
172 return $data;
173 }
174 $placeholders_meta = [ '{FIRST_NAME}', '{LAST_NAME}' ];
175 $placeholders_data = [ '{USER_LOGIN}', '{DISPLAY_NAME}' ];
176 $user = $this->getCurrentUser();
177 if ( $user ) {
178 foreach ( $placeholders_meta as $placeholder ) {
179 if ( strpos( $data, $placeholder ) === false ) { continue; }
180 $lcPlaceholder = substr( strtolower( $placeholder ), 1, -1 );
181 $value = get_user_meta( $user->ID, $lcPlaceholder, true );
182 $data = str_replace( $placeholder, $value, $data );
183 }
184 foreach ( $placeholders_data as $placeholder ) {
185 if ( strpos( $data, $placeholder ) === false ) { continue; }
186 $lcPlaceholder = substr( strtolower( $placeholder ), 1, -1 );
187 $value = $user->data->$lcPlaceholder;
188 $data = str_replace( $placeholder, $value, $data );
189 }
190 if ( !empty( $data ) ) {
191 return $data;
192 }
193 }
194 return $guestName;
195 }
196
197 public function formatUserName( $userName, $guestName = 'Guest: ' ) {
198 // Default avatar
199 if ( empty( $userName ) ) {
200 $user = $this->getCurrentUser();
201 if ( $user ) {
202 // Gravatar
203 $userName = '<div class="mwai-avatar"><img src="' . get_avatar_url( $user->user_email ) . '" /></div>';
204 }
205 else {
206 // Default avatar
207 $userName = '<div class="mwai-avatar mwai-svg"><img src="' . MWAI_URL . '/images/avatar-user.svg" /></div>';
208 }
209 }
210 // Custom avatar
211 else if ( $this->core->isUrl( $userName ) ) {
212 $userName = '<div class="mwai-avatar"><img src="' . $userName . '" /></div>';
213 }
214 // Placeholders
215 else {
216 $userName = $this->handlePlaceholders( $userName, $guestName );
217 $userName = '<div class="mwai-name-text">' . $userName . '</div>';
218 }
219 return $userName;
220 }
221
222 public function formatAiName( $aiName ) {
223 // Default avatar
224 if ( empty( $aiName ) ) {
225 $aiName = '<div class="mwai-avatar mwai-svg"><img src="' . MWAI_URL . '/images/avatar-ai.svg" /></div>';
226 }
227 // Custom avatar
228 else if ( $this->core->isUrl( $aiName ) ) {
229 $aiName = '<div class="mwai-avatar"><img src="' . $aiName . '" /></div>';
230 }
231 else {
232 $aiName = '<div class="mwai-name-text">' . $aiName . '</div>';
233 }
234 return $aiName;
235 }
236
237 public function formatRawName( $aiName ) {
238 return 'AI: ';
239 }
240
241 public function formatRawUserName( $userName, $guestName ) {
242 return 'User: ';
243 }
244
245 public function chat( $atts ) {
246 $this->usingChat = true;
247
248 // Use the core default parameters, or the user default parameters
249 $override = $this->core->get_option( 'shortcode_chat_params_override' );
250 $defaults_params = $override ? $this->core->get_option( 'shortcode_chat_params' ) :
251 $this->core->get_option( 'shortcode_chat_default_params' );
252
253 // Give a chance to modify the default parameters one last time
254 $defaults = apply_filters( 'mwai_chatbot_params_defaults', $defaults_params );
255
256 // Make sure all the mandatory params are set
257 foreach ( $this->core->defaultChatbotParams as $key => $value ) {
258 if ( !isset( $defaults[$key] ) ) {
259 $defaults[$key] = $value;
260 }
261 }
262
263 // Override with the shortcode, and before/after filters
264 $atts = apply_filters( 'mwai_chatbot_params_before', $atts );
265 $atts = shortcode_atts( $defaults, $atts );
266 $atts = apply_filters( 'mwai_chatbot_params', $atts );
267
268 // UI Parameters
269 $aiName = addslashes( trim( $atts['ai_name'] ) );
270 $userName = addslashes( trim( $atts['user_name'] ) );
271 $guestName = addslashes( trim( $atts['guest_name'] ) );
272 $sysName = addslashes( trim( $atts['sys_name'] ) );
273 $context = addslashes( $atts['context'] );
274 $context = preg_replace( '/\n/', "\\n", $context );
275 $textSend = addslashes( trim( $atts['text_send'] ) );
276 $textClear = addslashes( trim( $atts['text_clear'] ) );
277 $textInputMaxLength = intval( $atts['text_input_maxlength'] );
278 $textInputPlaceholder = addslashes( trim( $atts['text_input_placeholder'] ) );
279 $textCompliance = ( trim( $atts['text_compliance'] ) );
280 $startSentence = addslashes( trim( $atts['start_sentence'] ) );
281 $window = filter_var( $atts['window'], FILTER_VALIDATE_BOOLEAN );
282 $copyButton = filter_var( $atts['copy_button'], FILTER_VALIDATE_BOOLEAN );
283 $fullscreen = filter_var( $atts['fullscreen'], FILTER_VALIDATE_BOOLEAN );
284 $icon = isset( $atts['icon'] ) ? addslashes( trim( $atts['icon'] ) ) : '';
285 $iconText = trim( $atts['icon_text'] );
286 $iconAlt = addslashes( trim( $atts['icon_alt'] ) );
287 $iconPosition = addslashes( trim( $atts['icon_position'] ) );
288 $style = $atts['style'];
289
290 // Validade & Enhance UI Parameters
291 $aiName = $this->formatAiName( $aiName );
292 $userName = $this->formatUserName( $userName, $guestName );
293 $rawAiName = $this->formatRawName( $aiName );
294 $rawUserName = $this->formatRawUserName( $userName, $guestName );
295
296 // Chatbot System Parameters
297 $id = empty( $atts['id'] ) ? uniqid() : $atts['id'];
298 $typewriter = $this->core->get_option( 'shortcode_chat_typewriter' );
299 $memorizeChat = !empty( $atts['id'] );
300 $id = preg_replace( '/[^a-zA-Z0-9]/', '', $id );
301 $env = $atts['env'];
302 $mode = $atts['mode'];
303 $maxResults = $mode === 'chat' ? 1 : $atts['max_results'];
304 $maxSentences = !empty( $atts['max_sentences'] ) ? intval( $atts['max_sentences'] ) : 1;
305 $sessionId = $this->core->get_session_id();
306 $rest_nonce = wp_create_nonce( 'wp_rest' );
307 $casuallyFineTuned = boolval( $atts['casually_fine_tuned'] );
308 $embeddingsIndex = $atts['embeddings_index'];
309 $promptEnding = addslashes( trim( $atts['prompt_ending'] ) );
310 $completionEnding = addslashes( trim( $atts['completion_ending'] ) );
311 if ( $casuallyFineTuned ) {
312 $promptEnding = "\\n\\n###\\n\\n";
313 $completionEnding = "\\n\\n";
314 }
315 $debugMode = $this->core->get_option( 'debug_mode' );
316
317 // OpenAI Parameters
318 $model = $atts['model'];
319 $temperature = $atts['temperature'];
320 $maxTokens = $atts['max_tokens'];
321 $service = $atts['service'];
322 $apiKey = $atts['api_key'];
323
324 // Variables
325 $apiUrl = get_rest_url( null, $mode === 'images' ? 'ai-chatbot/v1/imagesbot' : 'ai-chatbot/v1/chat' );
326 $baseClasses = 'mwai-chat';
327 $baseClasses .= ( $window ? ' mwai-window' : '' );
328 $baseClasses .= ( !$window && $fullscreen ? ' mwai-fullscreen' : '' );
329 $baseClasses .= ( $style === 'chatgpt' ? ' mwai-chatgpt' : '' );
330 $baseClasses .= ( $window && !empty( $iconPosition ) ? ( ' mwai-' . $iconPosition ) : '' );
331
332 // Output CSS
333 ob_start();
334 $style_content = '';
335 if ( $style === 'chatgpt' ) {
336 $style_content = $this->chatgpt_style( $id, $style );
337 }
338 $style_content = apply_filters( 'mwai_chatbot_style', $style_content, $id );
339 echo wp_kses( $style_content, array( 'style' => array() ) );
340
341 // Output HTML & CSS
342 $chatStyles = $this->core->get_option( 'shortcode_chat_styles' );
343 $iconUrl = MWAI_URL . '/images/chat-green.svg';
344 if ( !empty( $icon ) ) {
345 $iconUrl = $icon;
346 }
347 else if ( !empty( $chatStyles ) && isset( $chatStyles['icon'] ) ) {
348 $url = $chatStyles['icon'];
349 $iconUrl = $this->core->isUrl( $url ) ? $url : ( MWAI_URL . 'images/' . $chatStyles['icon'] );
350 }
351 ?>
352 <div id="mwai-chat-<?php echo esc_attr( $id ); ?>" class="<?php echo esc_attr( $baseClasses ); ?>">
353 <?php if ( $window ) : ?>
354 <div class="mwai-open-button">
355 <?php if ( !empty( $iconText ) ) : ?>
356 <div class="mwai-icon-text"><?php echo esc_html( $iconText ); ?></div>
357 <?php endif; ?>
358 <img width="64" height="64" alt="<?php echo esc_attr( $iconAlt ); ?>" src="<?php echo esc_url( $iconUrl ); ?>" />
359 </div>
360 <div class="mwai-header">
361 <div class="mwai-buttons">
362 <?php if ( $fullscreen ) : ?>
363 <div class="mwai-resize-button"></div>
364 <?php endif; ?>
365 <div class="mwai-close-button"></div>
366 </div>
367 </div>
368 <?php endif; ?>
369 <div class="mwai-content">
370 <div class="mwai-conversation">
371 </div>
372 <div class="mwai-input">
373 <textarea rows="1" maxlength="<?php echo (int)$textInputMaxLength; ?>" placeholder="<?php echo esc_attr( $textInputPlaceholder ); ?>"></textarea>
374 <button><span><?php echo esc_html( $textSend ); ?></span></button>
375 </div>
376 <?php if ( !empty( $textCompliance ) ) : ?>
377 <div class="mwai-compliance">
378 ⚠️ <?php echo wp_kses_post( $textCompliance ); ?>
379 </div>
380 <?php endif; ?>
381 </div>
382 </div>
383
384 <script>
385 (function () {
386 let isMobile = window.matchMedia( "only screen and (max-width: 760px)" ).matches;
387 let isWindow = <?php echo $window ? 'true' : 'false' ?>;
388 let isDebugMode = <?php echo $debugMode ? 'true' : 'false' ?>;
389 let isFullscreen = <?php echo $fullscreen ? 'true' : 'false' ?>;
390 let restNonce = '<?php echo esc_attr( $rest_nonce ) ?>';
391 let apiURL = '<?php echo esc_url( $apiUrl ) ?>';
392 let isCasuallyFineTuned = <?php echo $casuallyFineTuned ? 'true' : 'false' ?>;
393 let rawUserName = '<?php echo esc_attr( $rawUserName ) ?>';
394 let rawAiName = '<?php echo esc_attr( $rawAiName ) ?>';
395 let userName = '<?php echo wp_kses_post( $userName ) ?>';
396 let aiName = '<?php echo wp_kses_post( $aiName ) ?>';
397 let sysName = '<?php echo wp_kses_post( $sysName ) ?>';
398 let env = '<?php echo esc_attr( $env ) ?>';
399 let apiKey = '<?php echo esc_attr( $apiKey ) ?>';
400 let service = '<?php echo esc_attr( $service ) ?>';
401 let session = '<?php echo esc_attr( $sessionId ) ?>';
402 let mode = '<?php echo esc_attr( $mode ) ?>';
403 let model = '<?php echo esc_attr( $model ) ?>';
404 let context = isCasuallyFineTuned ? null : '<?php echo esc_attr( $context ) ?>';
405 let embeddingsIndex = '<?php echo esc_attr( $embeddingsIndex ) ?>';
406 let promptEnding = '<?php echo esc_attr( $promptEnding ) ?>';
407 let stop = '<?php echo esc_attr( $completionEnding ) ?>';
408 let startSentence = '<?php echo esc_attr( $startSentence ) ?>';
409 let maxSentences = <?php echo (int)$maxSentences ?>;
410 let memorizeChat = <?php echo $memorizeChat ? 'true' : 'false' ?>;
411 let maxTokens = <?php echo (int)$maxTokens ?>;
412 let maxResults = <?php echo (int)$maxResults ?>;
413 let temperature = <?php echo str_replace(',', '.', (float)$temperature) ?>;
414 let typewriter = <?php echo $typewriter ? 'true' : 'false' ?>;
415 let copyButton = <?php echo $copyButton ? 'true' : 'false' ?>;
416 let clientId = randomStr();
417 let memorizedChat = { clientId, messages: [] };
418
419 if (isDebugMode) {
420 window.mwai_<?php echo esc_attr( $id ) ?> = {
421 memorizedChat: memorizedChat,
422 parameters: { mode: mode, model, temperature, maxTokens, context: context, startSentence,
423 isMobile, isWindow, isFullscreen, isCasuallyFineTuned, memorizeChat, maxSentences,
424 rawUserName, rawAiName, embeddingsIndex, typewriter, maxResults, userName, aiName, env, apiKey, service, session
425 }
426 };
427 }
428
429 function randomStr() {
430 return Math.random().toString(36).substring(2);
431 }
432
433 // Set button text
434 function setButtonText() {
435 let input = document.querySelector('#mwai-chat-<?php echo esc_attr( $id ) ?> .mwai-input textarea');
436 let button = document.querySelector('#mwai-chat-<?php echo esc_attr( $id ) ?> .mwai-input button');
437 let buttonSpan = button.querySelector('span');
438 if (memorizedChat.messages.length < 2) {
439 buttonSpan.innerHTML = '<?php echo esc_html( $textSend ); ?>';
440 }
441 else if (!input.value.length) {
442 button.classList.add('mwai-clear');
443 buttonSpan.innerHTML = '<?php echo esc_html( $textClear ); ?>';
444 }
445 else {
446 button.classList.remove('mwai-clear');
447 buttonSpan.innerHTML = '<?php echo esc_html( $textSend ); ?>';
448 }
449 }
450
451 // Inject timer
452 function injectTimer(element) {
453 let intervalId;
454 let startTime = new Date();
455 let timerElement = null;
456
457 function updateTimer() {
458 let now = new Date();
459 let timer = Math.floor((now - startTime) / 1000);
460 if (!timerElement) {
461 if (timer > 0.5) {
462 timerElement = document.createElement('div');
463 timerElement.classList.add('mwai-timer');
464 element.appendChild(timerElement);
465 }
466 }
467 if (timerElement) {
468 let minutes = Math.floor(timer / 60);
469 let seconds = timer - (minutes * 60);
470 seconds = seconds < 10 ? '0' + seconds : seconds;
471 let display = minutes + ':' + seconds;
472 timerElement.innerHTML = display;
473 }
474 }
475
476 intervalId = setInterval(updateTimer, 500);
477
478 return function stopTimer() {
479 clearInterval(intervalId);
480 if (timerElement) {
481 timerElement.remove();
482 }
483 };
484 }
485
486 // Push the reply in the conversation
487 function addReply(text, role = 'user', replay = false) {
488 var conversation = document.querySelector('#mwai-chat-<?php echo esc_attr( $id ) ?> .mwai-conversation');
489
490 if (memorizeChat) {
491 localStorage.setItem('mwai-chat-<?php echo esc_attr( $id ) ?>', JSON.stringify(memorizedChat));
492 }
493
494 // If text is array, then it's image URLs. Let's create a simple gallery in HTML in $text.
495 if (Array.isArray(text)) {
496 var newText = '<div class="mwai-gallery">';
497 for (var i = 0; i < text.length; i++) {
498 newText += '<a href="' + text[i] + '" target="_blank"><img src="' + text[i] + '" />';
499 }
500 text = newText + '</div>';
501 }
502
503 var mwaiClasses = ['mwai-reply'];
504 if (role === 'assistant') {
505 mwaiClasses.push('mwai-ai');
506 }
507 else if (role === 'system') {
508 mwaiClasses.push('mwai-system');
509 }
510 else {
511 mwaiClasses.push('mwai-user');
512 }
513 var div = document.createElement('div');
514 div.classList.add(...mwaiClasses);
515 var nameSpan = document.createElement('span');
516 nameSpan.classList.add('mwai-name');
517 if (role === 'assistant') {
518 nameSpan.innerHTML = aiName;
519 }
520 else if (role === 'system') {
521 nameSpan.innerHTML = sysName;
522 }
523 else {
524 nameSpan.innerHTML = userName;
525 }
526 var textSpan = document.createElement('span');
527 textSpan.classList.add('mwai-text');
528 textSpan.innerHTML = text;
529 div.appendChild(nameSpan);
530 div.appendChild(textSpan);
531
532 // Copy Button
533 if (copyButton && role === 'assistant') {
534 var button = document.createElement('div');
535 button.classList.add('mwai-copy-button');
536 var firstElement = document.createElement('div');
537 firstElement.classList.add('mwai-copy-button-one');
538 var secondElement = document.createElement('div');
539 secondElement.classList.add('mwai-copy-button-two');
540 button.appendChild(firstElement);
541 button.appendChild(secondElement);
542 div.appendChild(button);
543 button.addEventListener('click', function () {
544 try {
545 var content = textSpan.textContent;
546 navigator.clipboard.writeText(content);
547 button.classList.add('mwai-animate');
548 setTimeout(function () {
549 button.classList.remove('mwai-animate');
550 }, 1000);
551 }
552 catch (err) {
553 console.warn('Not allowed to copy to clipboard. Make sure your website uses HTTPS.');
554 }
555 });
556 }
557
558 conversation.appendChild(div);
559
560 if (typewriter) {
561 if (role === 'assistant' && text !== startSentence && !replay) {
562 let typewriter = new Typewriter(textSpan, {
563 deleteSpeed: 50, delay: 25, loop: false, cursor: '', autoStart: true,
564 wrapperClassName: 'mwai-typewriter',
565 });
566 typewriter.typeString(text).start().callFunction((state) => {
567 state.elements.cursor.setAttribute('hidden', 'hidden');
568 typewriter.stop();
569 });
570 }
571 }
572
573 conversation.scrollTop = conversation.scrollHeight;
574 setButtonText();
575
576 // Syntax coloring
577 if (typeof hljs !== 'undefined') {
578 document.querySelectorAll('pre code').forEach((el) => {
579 hljs.highlightElement(el);
580 });
581 }
582 }
583
584 function buildPrompt(last = 15) {
585 let prompt = context ? (context + '\n\n') : '';
586 memorizedChat.messages = memorizedChat.messages.slice(-last);
587
588 // Casually fine tuned, let's use the last question
589 if (isCasuallyFineTuned) {
590 let lastLine = memorizedChat.messages[memorizedChat.messages.length - 1];
591 prompt = lastLine.content + promptEnding;
592 return prompt;
593 }
594
595 // Otherwise let's compile the latest conversation
596 let conversation = memorizedChat.messages.map(x => x.who + x.content);
597 prompt += conversation.join('\n');
598 prompt += '\n' + rawAiName;
599 return prompt;
600 }
601
602 // Function to request the completion
603 function onSendClick() {
604 let input = document.querySelector('#mwai-chat-<?php echo esc_attr( $id ) ?> .mwai-input textarea');
605 let inputText = input.value.trim();
606
607 // Reset the conversation if empty
608 if (inputText === '') {
609 clientId = randomStr();
610 document.querySelector('#mwai-chat-<?php echo esc_attr( $id ) ?> .mwai-conversation').innerHTML = '';
611 localStorage.removeItem('mwai-chat-<?php echo esc_attr( $id ) ?>')
612 memorizedChat = { clientId: clientId, messages: [] };
613 memorizedChat.messages.push({
614 id: randomStr(),
615 role: 'assistant',
616 content: startSentence,
617 who: rawAiName,
618 html: startSentence
619 });
620 addReply(startSentence, 'assistant');
621 return;
622 }
623
624 // Disable the button
625 var button = document.querySelector('#mwai-chat-<?php echo esc_attr( $id ) ?> .mwai-input button');
626 button.disabled = true;
627
628 // Add the user reply
629 memorizedChat.messages.push({
630 id: randomStr(),
631 role: 'user',
632 content: inputText,
633 who: rawUserName,
634 html: inputText
635 });
636 addReply(inputText, 'user');
637 input.value = '';
638 input.setAttribute('rows', 1);
639 input.disabled = true;
640
641 let prompt = buildPrompt(maxSentences);
642
643 const data = mode === 'images' ? {
644 env, session: session,
645 prompt: inputText,
646 newMessage: inputText,
647 model: model,
648 maxResults,
649 apiKey: apiKey,
650 service: service,
651 clientId: clientId,
652 } : {
653 env, session: session,
654 prompt: prompt,
655 context: context,
656 messages: memorizedChat.messages,
657 newMessage: inputText,
658 userName: userName,
659 aiName: aiName,
660 model: model,
661 temperature: temperature,
662 maxTokens: maxTokens,
663 maxResults: 1,
664 apiKey: apiKey,
665 service: service,
666 embeddingsIndex: embeddingsIndex,
667 stop: stop,
668 clientId: clientId,
669 };
670
671 // Start the timer
672 const stopTimer = injectTimer(button);
673
674 // Send the request
675 if (isDebugMode) {
676 console.log('[BOT] Sent: ', data);
677 }
678 fetch(apiURL, { method: 'POST', headers: {
679 'Content-Type': 'application/json',
680 'X-WP-Nonce': restNonce,
681 },
682 body: JSON.stringify(data)
683 })
684 .then(response => response.json())
685 .then(data => {
686 if (isDebugMode) {
687 console.log('[BOT] Recv: ', data);
688 }
689 if (!data.success) {
690 addReply(data.message, 'system');
691 }
692 else {
693 let html = data.images ? data.images : data.html;
694 memorizedChat.messages.push({
695 id: randomStr(),
696 role: 'assistant',
697 content: data.answer,
698 who: rawAiName,
699 html: html
700 });
701 addReply(html, 'assistant');
702 }
703 button.disabled = false;
704 input.disabled = false;
705 stopTimer();
706
707 // Only focus only on desktop (to avoid the mobile keyboard to kick-in)
708 if (!isMobile) {
709 input.focus();
710 }
711 })
712 .catch(error => {
713 console.error(error);
714 button.disabled = false;
715 input.disabled = false;
716 stopTimer();
717 });
718 }
719
720 // Keep the textarea height in sync with the content
721 function resizeTextArea(ev) {
722 ev.target.style.height = 'auto';
723 ev.target.style.height = ev.target.scrollHeight + 'px';
724 }
725
726 // Keep the textarea height in sync with the content
727 function delayedResizeTextArea(ev) {
728 window.setTimeout(resizeTextArea, 0, event);
729 }
730
731 // Init the chatbot
732 function initMeowChatbot() {
733 var input = document.querySelector('#mwai-chat-<?php echo esc_attr( $id ) ?> .mwai-input textarea');
734 var button = document.querySelector('#mwai-chat-<?php echo esc_attr( $id ) ?> .mwai-input button');
735
736 input.addEventListener('keypress', (event) => {
737 let text = event.target.value;
738 if (event.keyCode === 13 && !text.length && !event.shiftKey) {
739 event.preventDefault();
740 return;
741 }
742 if (event.keyCode === 13 && text.length && !event.shiftKey) {
743 onSendClick();
744 }
745 });
746 input.addEventListener('keydown', (event) => {
747 var rows = input.getAttribute('rows');
748 if (event.keyCode === 13 && event.shiftKey) {
749 var lines = input.value.split('\n').length + 1;
750 //mwaiSetTextAreaHeight(input, lines);
751 }
752 });
753 input.addEventListener('keyup', (event) => {
754 var rows = input.getAttribute('rows');
755 var lines = input.value.split('\n').length ;
756 //mwaiSetTextAreaHeight(input, lines);
757 setButtonText();
758 });
759
760 input.addEventListener('change', resizeTextArea, false);
761 input.addEventListener('cut', delayedResizeTextArea, false);
762 input.addEventListener('paste', delayedResizeTextArea, false);
763 input.addEventListener('drop', delayedResizeTextArea, false);
764 input.addEventListener('keydown', delayedResizeTextArea, false);
765
766 button.addEventListener('click', (event) => {
767 onSendClick();
768 });
769
770 // If window, add event listener to mwai-open-button and mwai-close-button
771 if ( isWindow ) {
772 var openButton = document.querySelector('#mwai-chat-<?php echo esc_attr( $id ) ?> .mwai-open-button');
773 openButton.addEventListener('click', (event) => {
774 var chat = document.querySelector('#mwai-chat-<?php echo esc_attr( $id ) ?>');
775 chat.classList.add('mwai-open');
776 // Only focus only on desktop (to avoid the mobile keyboard to kick-in)
777 if (!isMobile) {
778 input.focus();
779 }
780 });
781 var closeButton = document.querySelector('#mwai-chat-<?php echo esc_attr( $id ) ?> .mwai-close-button');
782 closeButton.addEventListener('click', (event) => {
783 var chat = document.querySelector('#mwai-chat-<?php echo esc_attr( $id ) ?>');
784 chat.classList.remove('mwai-open');
785 });
786 if (isFullscreen) {
787 var resizeButton = document.querySelector('#mwai-chat-<?php echo esc_attr( $id ) ?> .mwai-resize-button');
788 resizeButton.addEventListener('click', (event) => {
789 var chat = document.querySelector('#mwai-chat-<?php echo esc_attr( $id ) ?>');
790 chat.classList.toggle('mwai-fullscreen');
791 });
792 }
793 }
794
795 // Get back the previous chat if any for the same ID
796 var chatHistory = [];
797 if (memorizeChat) {
798 chatHistory = localStorage.getItem('mwai-chat-<?php echo esc_attr( $id ) ?>');
799 if (chatHistory) {
800 memorizedChat = JSON.parse(chatHistory);
801 if (memorizedChat && memorizedChat.clientId && memorizedChat.messages) {
802 clientId = memorizedChat.clientId;
803 memorizedChat.messages = memorizedChat.messages.filter(x => x && x.html && x.role);
804 memorizedChat.messages.forEach(x => {
805 addReply(x.html, x.role, true);
806 });
807 }
808 else {
809 memorizedChat = null;
810 }
811 }
812 if (!memorizedChat) {
813 memorizedChat = {
814 clientId: clientId,
815 messages: []
816 };
817 }
818 }
819 if (memorizedChat.messages.length === 0) {
820 memorizedChat.messages.push({
821 id: randomStr(),
822 role: 'assistant',
823 content: startSentence,
824 who: rawAiName,
825 html: startSentence
826 });
827 addReply(startSentence, 'assistant');
828 }
829 }
830
831 // Let's go totally meoooow on this!
832 initMeowChatbot();
833 })();
834 </script>
835
836 <?php
837 $output = ob_get_contents();
838 ob_end_clean();
839 $output = apply_filters( 'mwai_chatbot', $output, $atts );
840 return $output;
841 }
842 }
843