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