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