PluginProbe ʕ •ᴥ•ʔ
AI Engine – The Chatbot, AI Framework & MCP for WordPress / 1.0.4
AI Engine – The Chatbot, AI Framework & MCP for WordPress v1.0.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.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
693 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 $textAreaResizeFn = "mwai_{$id}_textAreaResize";
273 $textAreaDelayedResizeFn = "mwai_{$id}_textAreaDelayedResize";
274
275 // Variables
276 $apiUrl = get_rest_url( null, $mode === 'images' ? 'ai-chatbot/v1/imagesbot' : 'ai-chatbot/v1/chat' );
277 $onGoingPrompt = "mwai_{$id}_onGoingPrompt";
278 $memorizedChat = "mwai_{$id}_memorizedChat";
279 $baseClasses = "mwai-chat";
280 $baseClasses .= ( $window ? " mwai-window" : "" );
281 $baseClasses .= ( !$window && $fullscreen ? " mwai-fullscreen" : "" );
282 $baseClasses .= ( $style === 'chatgpt' ? " mwai-chatgpt" : "" );
283 $baseClasses .= ( $window && !empty( $iconPosition ) ? (" mwai-" . $iconPosition) : "" );
284
285 // Output CSS
286 ob_start();
287 $style_content = "";
288 if ( $style === 'chatgpt' ) {
289 $style_content = $this->chatgpt_style( $id, $style );
290 }
291 echo apply_filters( 'mwai_chatbot_style', $style_content, $id );
292
293 // Output HTML & CSS
294 $chatStyles = $this->core->get_option( 'shortcode_chat_styles' );
295 $iconUrl = MWAI_URL . '/images/chat-green.svg';
296 if ( !empty( $icon ) ) {
297 $iconUrl = $icon;
298 }
299 else if ( !empty( $chatStyles ) && isset( $chatStyles['icon'] ) ) {
300 $url = $chatStyles['icon'];
301 $iconUrl = $this->core->isUrl( $url ) ? $url : (MWAI_URL . 'images/' . $chatStyles['icon']);
302 }
303 ?>
304 <div id="mwai-chat-<?= $id ?>" class="<?= $baseClasses ?>">
305 <?php if ( $window ) { ?>
306 <div class="mwai-open-button">
307 <?php if ( !empty( $iconText ) ) { ?>
308 <div class="mwai-icon-text"><?= $iconText ?></div>
309 <?php } ?>
310 <img width="64" height="64" src="<?= $iconUrl ?>" />
311 </div>
312 <div class="mwai-header">
313 <?php if ( $fullscreen ) { ?>
314 <div class="mwai-resize-button"></div>
315 <?php } ?>
316 <div class="mwai-close-button"></div>
317 </div>
318 <?php } ?>
319 <div class="mwai-content">
320 <div class="mwai-conversation">
321 </div>
322 <div class="mwai-input">
323 <textarea rows="1" placeholder="<?= $textInputPlaceholder ?>"></textarea>
324 <button><span><?= $textSend ?></span></button>
325 </div>
326 </div>
327 </div>
328
329 <script>
330 (function () {
331 let <?= $onGoingPrompt ?> = [];
332 let isMobile = window.matchMedia("only screen and (max-width: 760px)").matches;
333 let isWindow = <?= $window ? 'true' : 'false' ?>;
334 let isDebugMode = <?= $debugMode ? 'true' : 'false' ?>;
335 let isFullscreen = <?= $fullscreen ? 'true' : 'false' ?>;
336 let isCasuallyFineTuned = <?= $casuallyFineTuned ? 'true' : 'false' ?>;
337 let mode = '<?= $mode ?>';
338 let maxSentences = <?= $maxSentences ?>;
339 let memorizeChat = <?= $memorizeChat ? 'true' : 'false' ?>;
340 let <?= $memorizedChat ?> = [];
341
342 if (isDebugMode) {
343 window.mwai_<?= $id ?> = {
344 onGoingPrompt: <?= $onGoingPrompt ?>,
345 memorizedChat: <?= $memorizedChat ?>,
346 parameters: {
347 mode: mode,
348 model: '<?= $model ?>',
349 temperature: '<?= $temperature ?>',
350 maxTokens: '<?= $maxTokens ?>',
351 context: '<?= $context ?>',
352 start_sentence: '<?= $startSentence ?>',
353 isMobile: isMobile,
354 isWindow: isWindow,
355 isFullscreen: isFullscreen,
356 isCasuallyFineTuned: isCasuallyFineTuned,
357 }
358 };
359 }
360
361 // Set button text
362 function <?= $setButtonTextFn ?>() {
363 let input = document.querySelector('#mwai-chat-<?= $id ?> .mwai-input textarea');
364 let button = document.querySelector('#mwai-chat-<?= $id ?> .mwai-input button');
365 let buttonSpan = button.querySelector('span');
366 if (<?= $memorizedChat ?>.length < 2) {
367 buttonSpan.innerHTML = '<?= $textSend ?>';
368 }
369 else if (!input.value.length) {
370 button.classList.add('mwai-clear');
371 buttonSpan.innerHTML = '<?= $textClear ?>';
372 }
373 else {
374 button.classList.remove('mwai-clear');
375 buttonSpan.innerHTML = '<?= $textSend ?>';
376 }
377 }
378
379 // Inject timer
380 function <?= $injectTimerFn ?>(element) {
381 let intervalId;
382 let startTime = new Date();
383 let timerElement = null;
384
385 function updateTimer() {
386 let now = new Date();
387 let timer = Math.floor((now - startTime) / 1000);
388 if (!timerElement) {
389 if (timer > 0.5) {
390 timerElement = document.createElement('div');
391 timerElement.classList.add('mwai-timer');
392 element.appendChild(timerElement);
393 }
394 }
395 if (timerElement) {
396 let minutes = Math.floor(timer / 60);
397 let seconds = timer - (minutes * 60);
398 seconds = seconds < 10 ? "0" + seconds : seconds;
399 let display = minutes + ":" + seconds;
400 timerElement.innerHTML = display;
401 }
402 }
403
404 intervalId = setInterval(updateTimer, 500);
405
406 return function stopTimer() {
407 clearInterval(intervalId);
408 if (timerElement) {
409 timerElement.remove();
410 }
411 };
412 }
413
414 // Push the reply in the conversation
415 function <?= $addReplyFn ?>(text, type = 'user') {
416 var conversation = document.querySelector('#mwai-chat-<?= $id ?> .mwai-conversation');
417
418 if (memorizeChat) {
419 <?= $memorizedChat ?>.push({ text, type });
420 localStorage.setItem('mwai-chat-<?= $id ?>', JSON.stringify(<?= $memorizedChat ?>));
421 }
422
423 // If text is array, then it's image URLs. Let's create a simple gallery in HTML in $text.
424 if (Array.isArray(text)) {
425 var newText = '<div class="mwai-gallery">';
426 for (var i = 0; i < text.length; i++) {
427 newText += '<a href="' + text[i] + '" target="_blank"><img src="' + text[i] + '" />';
428 }
429 text = newText + '</div>';
430 }
431
432 var mwaiClasses = 'mwai-reply';
433 if (type === 'ai') {
434 mwaiClasses += ' mwai-ai';
435 }
436 else if (type === 'system') {
437 mwaiClasses += ' mwai-system';
438 }
439 else {
440 mwaiClasses += ' mwai-user';
441 }
442 var html = '<div class="' + mwaiClasses + '">';
443 if (type === 'ai') {
444 html += '<span class="mwai-name"><?= $aiName ?></span>';
445 }
446 else if (type === 'system') {
447 html += '<span class="mwai-name"><?= $sysName ?></span>';
448 }
449 else {
450 html += '<span class="mwai-name"><?= $userName ?></span>';
451 }
452 html += '<span class="mwai-text">' + text + '</span>';
453 html += '</div>';
454 conversation.innerHTML += html;
455 conversation.scrollTop = conversation.scrollHeight;
456 <?= $setButtonTextFn ?>();
457
458 // Syntax coloring
459 if (typeof hljs !== 'undefined') {
460 document.querySelectorAll('pre code').forEach((el) => {
461 hljs.highlightElement(el);
462 });
463 }
464 }
465
466 function <?= $onTidyOnGoingPromptFn ?>(onGoingPrompt, last = 15) {
467 let onGoingPromptLength = onGoingPrompt.length;
468 let start = (onGoingPromptLength - last) < 0 ? 0 : (onGoingPromptLength - last);
469 if (isCasuallyFineTuned) { onGoingPromptLength--; }
470 let conversationToUse = onGoingPrompt.slice(start, onGoingPromptLength);
471
472 // Casually fine tuned, let's use the last question
473 if (isCasuallyFineTuned) {
474 let lastLine = conversationToUse[conversationToUse.length - 1];
475 let prompt = lastLine.says + '<?= $promptEnding ?>'
476 return prompt;
477 }
478
479 // Otherwise let's compile the latest conversation
480 conversationToUse = conversationToUse.map(x => x.who + x.says);
481 let prompt = conversationToUse.join('\n');
482 if (isCasuallyFineTuned) {
483 prompt = '<?= $promptEnding ?>';
484 }
485 return prompt;
486 }
487
488 // Function to request the completion
489 function <?= $onSentClickFn ?>() {
490 let input = document.querySelector('#mwai-chat-<?= $id ?> .mwai-input textarea');
491 let inputText = input.value.trim();
492
493 // Reset the conversation if empty
494 if (inputText === '') {
495 <?= $onGoingPrompt ?> = [];
496 document.querySelector('#mwai-chat-<?= $id ?> .mwai-conversation').innerHTML = '';
497 localStorage.removeItem('mwai-chat-<?= $id ?>');
498 <?= $memorizedChat ?> = [];
499 <?= $addReplyFn ?>('<?= $startSentence ?>', 'ai');
500 return;
501 }
502
503 // Disable the button
504 var button = document.querySelector('#mwai-chat-<?= $id ?> .mwai-input button');
505 button.disabled = true;
506
507 // Add the user reply
508 <?= $addReplyFn ?>(inputText, 'user');
509 <?= $onGoingPrompt ?>.push({ who: '<?= $rawUserName ?>', says: inputText });
510 input.value = '';
511 input.setAttribute('rows', 1);
512 input.disabled = true;
513
514 // Let's build the prompt depending on the "system"
515 <?= $onGoingPrompt ?>.push({ who: '<?= $rawAiName ?>', says: '' });
516 let prompt = '<?= $context ?>' + '\n\n';
517 prompt += <?= $onTidyOnGoingPromptFn ?>(<?= $onGoingPrompt ?>, maxSentences);
518
519 console.log('onGoingPrompt', <?= $onGoingPrompt ?>);
520 console.log('prompt', prompt);
521
522 // Prompt for the images
523 const data = mode === 'images' ? {
524 env: '<?= $env ?>',
525 session: '<?= $sessionId ?>',
526 prompt: inputText,
527 rawInput: inputText,
528 maxResults: <?= $maxResults ?>,
529 model: '<?= $atts['model'] ?>',
530 apiKey: '<?= $atts['api_key'] ?>',
531 // Prompt for the chat
532 } : {
533 env: '<?= $env ?>',
534 session: '<?= $sessionId ?>',
535 prompt: prompt,
536 rawInput: inputText,
537 userName: '<?= $userName ?>',
538 aiName: '<?= $aiName ?>',
539 model: '<?= $model ?>',
540 temperature: '<?= $temperature ?>',
541 maxTokens: '<?= $maxTokens ?>',
542 stop: '<?= $completionEnding ?>',
543 maxResults: 1,
544 apiKey: '<?= $apiKey ?>',
545 };
546
547 // Start the timer
548 const stopTimer = <?= $injectTimerFn ?>(button);
549
550 // Send the request
551 if (isDebugMode) {
552 console.log('[BOT] Sent: ', data);
553 }
554 fetch('<?= $apiUrl ?>', { method: 'POST', headers: {
555 'Content-Type': 'application/json',
556 'X-WP-Nonce': '<?= $rest_nonce ?>'
557 },
558 body: JSON.stringify(data)
559 })
560 .then(response => response.json())
561 .then(data => {
562 if (isDebugMode) {
563 console.log('[BOT] Recv: ', data);
564 }
565 if (!data.success) {
566 <?= $addReplyFn ?>(data.message, 'system');
567 }
568 else {
569 <?= $addReplyFn ?>(data.images ? data.images : data.html, 'ai');
570 <?= $onGoingPrompt ?>[<?= $onGoingPrompt ?>.length - 1].says = data.answer;
571 }
572 button.disabled = false;
573 input.disabled = false;
574 stopTimer();
575
576 // Only focus only on desktop (to avoid the mobile keyboard to kick-in)
577 if (!isMobile) {
578 input.focus();
579 }
580 })
581 .catch(error => {
582 console.error(error);
583 button.disabled = false;
584 input.disabled = false;
585 stopTimer();
586 });
587 }
588
589 // Keep the textarea height in sync with the content
590 function <?= $textAreaResizeFn ?>(ev) {
591 ev.target.style.height = 'auto';
592 ev.target.style.height = ev.target.scrollHeight + 'px';
593 }
594
595 // Keep the textarea height in sync with the content
596 function <?= $textAreaDelayedResizeFn ?>(ev) {
597 window.setTimeout(<?= $textAreaResizeFn ?>, 0, event);
598 }
599
600 // Init the chatbot
601 function <?= $initChatBotFn ?>() {
602 var input = document.querySelector('#mwai-chat-<?= $id ?> .mwai-input textarea');
603 var button = document.querySelector('#mwai-chat-<?= $id ?> .mwai-input button');
604
605 input.addEventListener('keypress', (event) => {
606 let text = event.target.value;
607 if (event.keyCode === 13 && !text.length && !event.shiftKey) {
608 event.preventDefault();
609 return;
610 }
611 if (event.keyCode === 13 && text.length && !event.shiftKey) {
612 <?= $onSentClickFn ?>();
613 }
614 });
615 input.addEventListener('keydown', (event) => {
616 var rows = input.getAttribute('rows');
617 if (event.keyCode === 13 && event.shiftKey) {
618 var lines = input.value.split('\n').length + 1;
619 //mwaiSetTextAreaHeight(input, lines);
620 }
621 });
622 input.addEventListener('keyup', (event) => {
623 var rows = input.getAttribute('rows');
624 var lines = input.value.split('\n').length ;
625 //mwaiSetTextAreaHeight(input, lines);
626 <?= $setButtonTextFn ?>();
627 });
628
629 input.addEventListener('change', <?= $textAreaResizeFn ?>, false);
630 input.addEventListener('cut', <?= $textAreaDelayedResizeFn ?>, false);
631 input.addEventListener('paste', <?= $textAreaDelayedResizeFn ?>, false);
632 input.addEventListener('drop', <?= $textAreaDelayedResizeFn ?>, false);
633 input.addEventListener('keydown', <?= $textAreaDelayedResizeFn ?>, false);
634
635 button.addEventListener('click', (event) => {
636 <?= $onSentClickFn ?>();
637 });
638
639 // If window, add event listener to mwai-open-button and mwai-close-button
640 if ( isWindow ) {
641 var openButton = document.querySelector('#mwai-chat-<?= $id ?> .mwai-open-button');
642 openButton.addEventListener('click', (event) => {
643 var chat = document.querySelector('#mwai-chat-<?= $id ?>');
644 chat.classList.add('mwai-open');
645 // Only focus only on desktop (to avoid the mobile keyboard to kick-in)
646 if (!isMobile) {
647 input.focus();
648 }
649 });
650 var closeButton = document.querySelector('#mwai-chat-<?= $id ?> .mwai-close-button');
651 closeButton.addEventListener('click', (event) => {
652 var chat = document.querySelector('#mwai-chat-<?= $id ?>');
653 chat.classList.remove('mwai-open');
654 });
655 if (isFullscreen) {
656 var resizeButton = document.querySelector('#mwai-chat-<?= $id ?> .mwai-resize-button');
657 resizeButton.addEventListener('click', (event) => {
658 var chat = document.querySelector('#mwai-chat-<?= $id ?>');
659 chat.classList.toggle('mwai-fullscreen');
660 });
661 }
662 }
663
664 // Get back the previous chat if any for the same ID
665 var chatHistory = [];
666 if (memorizeChat) {
667 chatHistory = localStorage.getItem('mwai-chat-<?= $id ?>');
668 if (chatHistory) {
669 chatHistory = JSON.parse(chatHistory);
670 chatHistory = chatHistory.filter(x => x && x.text && x.type);
671 chatHistory.forEach(x => { <?= $addReplyFn ?>(x.text, x.type) });
672 }
673 else {
674 chatHistory = [];
675 }
676 }
677 if (chatHistory.length === 0) {
678 <?= $addReplyFn ?>('<?= $startSentence ?>', 'ai');
679 }
680 }
681
682 // Let's go totally meoooow on this!
683 <?= $initChatBotFn ?>();
684 })();
685 </script>
686
687 <?php
688 $output = ob_get_contents();
689 ob_end_clean();
690 $output = apply_filters( 'mwai_chatbot', $output, $atts );
691 return $output;
692 }
693 }