PluginProbe ʕ •ᴥ•ʔ
AI Engine – The Chatbot, AI Framework & MCP for WordPress / 0.9.85
AI Engine – The Chatbot, AI Framework & MCP for WordPress v0.9.85
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
668 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 }
168 return $userName;
169 }
170
171 function formatAiName( $aiName ) {
172 // Default avatar
173 if ( empty( $aiName ) ) {
174 $aiName = '<div class="mwai-avatar mwai-svg"><img src="' . MWAI_URL . '/images/avatar-ai.svg" /></div>';
175 }
176 // Custom avatar
177 else if ( $this->core->isUrl( $aiName ) ) {
178 $aiName = '<div class="mwai-avatar"><img src="' . $aiName . '" /></div>';
179 }
180 return $aiName;
181 }
182
183 function formatRawName( $aiName ) {
184 return "AI: ";
185 }
186
187 function formatRawUserName( $userName, $guestName ) {
188 return "User: ";
189 }
190
191 function chat( $atts ) {
192 // Use the core default parameters, or the user default parameters
193 $override = $this->core->get_option( 'shortcode_chat_params_override' );
194 $defaults_params = $override ? $this->core->get_option( 'shortcode_chat_params' ) :
195 $this->core->get_option( 'shortcode_chat_default_params' );
196
197 // Give a chance to modify the default parameters one last time
198 $defaults = apply_filters( 'mwai_chatbot_params_defaults', $defaults_params );
199
200 // Make sure all the mandatory params are set
201 foreach ( $this->core->defaultChatbotParams as $key => $value ) {
202 if ( !isset( $defaults[$key] ) ) {
203 $defaults[$key] = $value;
204 }
205 }
206
207 // Override with the shortcode, and before/after filters
208 $atts = apply_filters( 'mwai_chatbot_params_before', $atts );
209 $atts = shortcode_atts( $defaults, $atts );
210 $atts = apply_filters( 'mwai_chatbot_params', $atts );
211
212 // UI Parameters
213 $aiName = addslashes( trim($atts['ai_name']) );
214 $userName = addslashes( trim($atts['user_name']) );
215 $guestName = addslashes( trim($atts['guest_name']) );
216 $sysName = addslashes( trim($atts['sys_name']) );
217 $context = addslashes( $atts['context'] );
218 $context = preg_replace( '/\v+/', "\\n", $context );
219 $textSend = addslashes( trim( $atts['text_send'] ) );
220 $textClear = addslashes( trim( $atts['text_clear'] ) );
221 $textInputPlaceholder = addslashes( trim( $atts['text_input_placeholder'] ) );
222 $startSentence = addslashes( trim( $atts['start_sentence'] ) );
223 $window = filter_var( $atts['window'], FILTER_VALIDATE_BOOLEAN );
224 $fullscreen = filter_var( $atts['fullscreen'], FILTER_VALIDATE_BOOLEAN );
225 $icon = addslashes( trim($atts['icon']) );
226 $iconText = trim($atts['icon_text']);
227 $iconPosition = addslashes( trim($atts['icon_position']) );
228 $style = $atts['style'];
229
230 // Validade & Enhance UI Parameters
231 $aiName = $this->formatAiName( $aiName );
232 $userName = $this->formatUserName( $userName, $guestName );
233 $rawAiName = $this->formatRawName( $aiName );
234 $rawUserName = $this->formatRawUserName( $userName, $guestName );
235
236 // Chatbot System Parameters
237 $id = empty( $atts['id'] ) ? uniqid() : $atts['id'];
238 $memorizeChat = !empty( $atts['id'] );
239 $id = preg_replace( '/[^a-zA-Z0-9]/', '', $id );
240 $env = $atts['env'];
241 $mode = $atts['mode'];
242 $maxResults = $atts['max_results'];
243 $sessionId = $this->core->get_session_id();
244 $rest_nonce = wp_create_nonce( 'wp_rest' );
245 $casuallyFineTuned = boolval( $atts['casually_fine_tuned'] );
246 $promptEnding = addslashes( trim( $atts['prompt_ending'] ) );
247 $completionEnding = addslashes( trim( $atts['completion_ending'] ) );
248 if ( $casuallyFineTuned ) {
249 $promptEnding = "\\n\\n===\\n\\n";
250 $completionEnding = "\\n\\n";
251 }
252 $debugMode = $chatStyles = $this->core->get_option( 'debug_mode' );
253
254 // OpenAI Parameters
255 $model = $atts['model'];
256 $temperature = $atts['temperature'];
257 $maxTokens = $atts['max_tokens'];
258 $apiKey = $atts['api_key'];
259
260 // Named functions
261 $onSentClickFn = "mwai_{$id}_onSendClick";
262 $addReplyFn = "mwai_{$id}_addReply";
263 $initChatBotFn = "mwai_{$id}_initChatBot";
264 $setButtonTextFn = "mwai_{$id}_setButtonText";
265 $onTidyOnGoingPromptFn = "mwai_{$id}_onUpdateOnGoingPrompt";
266 $injectTimerFn = "mwai_{$id}_injectTimer";
267
268 // Variables
269 $apiUrl = get_rest_url( null, $mode === 'images' ? 'ai-chatbot/v1/imagesbot' : 'ai-chatbot/v1/chat' );
270 $onGoingPrompt = "mwai_{$id}_onGoingPrompt";
271 $memorizedChat = "mwai_{$id}_memorizedChat";
272 $baseClasses = "mwai-chat";
273 $baseClasses .= ( $window ? " mwai-window" : "" );
274 $baseClasses .= ( !$window && $fullscreen ? " mwai-fullscreen" : "" );
275 $baseClasses .= ( $style === 'chatgpt' ? " mwai-chatgpt" : "" );
276 $baseClasses .= ( $window && !empty( $iconPosition ) ? (" mwai-" . $iconPosition) : "" );
277
278 // Output CSS
279 ob_start();
280 $style_content = "";
281 if ( $style === 'chatgpt' ) {
282 $style_content = $this->chatgpt_style( $id, $style );
283 }
284 echo apply_filters( 'mwai_chatbot_style', $style_content, $id );
285
286 // Output HTML & CSS
287 $chatStyles = $this->core->get_option( 'shortcode_chat_styles' );
288 $iconUrl = MWAI_URL . '/images/chat-green.svg';
289 if ( !empty( $icon ) ) {
290 $iconUrl = $icon;
291 }
292 else if ( !empty( $chatStyles ) && isset( $chatStyles['icon'] ) ) {
293 $url = $chatStyles['icon'];
294 $iconUrl = $this->core->isUrl( $url ) ? $url : (MWAI_URL . 'images/' . $chatStyles['icon']);
295 }
296 ?>
297 <div id="mwai-chat-<?= $id ?>" class="<?= $baseClasses ?>">
298 <?php if ( $window ) { ?>
299 <div class="mwai-open-button">
300 <?php if ( !empty( $iconText ) ) { ?>
301 <div class="mwai-icon-text"><?= $iconText ?></div>
302 <?php } ?>
303 <img width="64" height="64" src="<?= $iconUrl ?>" />
304 </div>
305 <div class="mwai-header">
306 <?php if ( $fullscreen ) { ?>
307 <div class="mwai-resize-button"></div>
308 <?php } ?>
309 <div class="mwai-close-button"></div>
310 </div>
311 <?php } ?>
312 <div class="mwai-content">
313 <div class="mwai-conversation">
314 </div>
315 <div class="mwai-input">
316 <textarea rows="1" placeholder="<?= $textInputPlaceholder ?>"></textarea>
317 <button><span><?= $textSend ?></span></button>
318 </div>
319 </div>
320 </div>
321
322 <script>
323 (function () {
324 let <?= $onGoingPrompt ?> = [];
325 let isMobile = window.matchMedia("only screen and (max-width: 760px)").matches;
326 let isWindow = <?= $window ? 'true' : 'false' ?>;
327 let isDebugMode = <?= $debugMode ? 'true' : 'false' ?>;
328 let isFullscreen = <?= $fullscreen ? 'true' : 'false' ?>;
329 let mode = '<?= $mode ?>';
330 let memorizeChat = <?= $memorizeChat ? 'true' : 'false' ?>;
331 let <?= $memorizedChat ?> = [];
332
333 if (isDebugMode) {
334 window.mwai_<?= $id ?> = {
335 onGoingPrompt: <?= $onGoingPrompt ?>,
336 memorizedChat: <?= $memorizedChat ?>,
337 parameters: {
338 mode: mode,
339 context: '<?= $context ?>',
340 isMobile: isMobile,
341 isWindow: isWindow,
342 isFullscreen: isFullscreen,
343 }
344 };
345 }
346
347 // Set button text
348 function <?= $setButtonTextFn ?>() {
349 let input = document.querySelector('#mwai-chat-<?= $id ?> .mwai-input textarea');
350 let button = document.querySelector('#mwai-chat-<?= $id ?> .mwai-input button');
351 let buttonSpan = button.querySelector('span');
352 if (<?= $memorizedChat ?>.length < 2) {
353 buttonSpan.innerHTML = '<?= $textSend ?>';
354 }
355 else if (!input.value.length) {
356 buttonSpan.innerHTML = '<?= $textClear ?>';
357 }
358 else {
359 buttonSpan.innerHTML = '<?= $textSend ?>';
360 }
361 }
362
363 // Inject timer
364 function <?= $injectTimerFn ?>(element) {
365 let intervalId;
366 let startTime = new Date();
367 let timerElement = null;
368
369 function updateTimer() {
370 let now = new Date();
371 let timer = Math.floor((now - startTime) / 1000);
372 if (!timerElement) {
373 if (timer > 0.5) {
374 timerElement = document.createElement('div');
375 timerElement.classList.add('mwai-timer');
376 element.appendChild(timerElement);
377 }
378 }
379 if (timerElement) {
380 let minutes = Math.floor(timer / 60);
381 let seconds = timer - (minutes * 60);
382 seconds = seconds < 10 ? "0" + seconds : seconds;
383 let display = minutes + ":" + seconds;
384 timerElement.innerHTML = display;
385 }
386 }
387
388 intervalId = setInterval(updateTimer, 500);
389
390 return function stopTimer() {
391 clearInterval(intervalId);
392 if (timerElement) {
393 timerElement.remove();
394 }
395 };
396 }
397
398 // Push the reply in the conversation
399 function <?= $addReplyFn ?>(text, type = 'user') {
400 var conversation = document.querySelector('#mwai-chat-<?= $id ?> .mwai-conversation');
401
402 if (memorizeChat) {
403 <?= $memorizedChat ?>.push({ text, type });
404 localStorage.setItem('mwai-chat-<?= $id ?>', JSON.stringify(<?= $memorizedChat ?>));
405 }
406
407 // If text is array, then it's image URLs. Let's create a simple gallery in HTML in $text.
408 if (Array.isArray(text)) {
409 var newText = '<div class="mwai-gallery">';
410 for (var i = 0; i < text.length; i++) {
411 newText += '<a href="' + text[i] + '" target="_blank"><img src="' + text[i] + '" />';
412 }
413 text = newText + '</div>';
414 }
415
416 var mwaiClasses = 'mwai-reply';
417 if (type === 'ai') {
418 mwaiClasses += ' mwai-ai';
419 }
420 else if (type === 'system') {
421 mwaiClasses += ' mwai-system';
422 }
423 else {
424 mwaiClasses += ' mwai-user';
425 }
426 var html = '<div class="' + mwaiClasses + '">';
427 if (type === 'ai') {
428 html += '<span class="mwai-name"><?= $aiName ?></span>';
429 }
430 else if (type === 'system') {
431 html += '<span class="mwai-name"><?= $sysName ?></span>';
432 }
433 else {
434 html += '<span class="mwai-name"><?= $userName ?></span>';
435 }
436 html += '<span class="mwai-text">' + text + '</span>';
437 html += '</div>';
438 conversation.innerHTML += html;
439 conversation.scrollTop = conversation.scrollHeight;
440 <?= $setButtonTextFn ?>();
441
442 // Syntax coloring
443 if (typeof hljs !== 'undefined') {
444 document.querySelectorAll('pre code').forEach((el) => {
445 hljs.highlightElement(el);
446 });
447 }
448 }
449
450 function <?= $onTidyOnGoingPromptFn ?>(onGoingPrompt, last = 15, casuallyFineTuned = false) {
451 let onGoingPromptLength = onGoingPrompt.length;
452 let start = (onGoingPromptLength - last) < 0 ? 0 : (onGoingPromptLength - last);
453 if (casuallyFineTuned) { onGoingPromptLength--; }
454 let conversationToUse = onGoingPrompt.slice(start, onGoingPromptLength);
455
456 // Casually fine tuned, let's use the last question
457 if (casuallyFineTuned) {
458 let lastLine = conversationToUse[conversationToUse.length - 1];
459 let prompt = lastLine.says + '<?= $promptEnding ?>'
460 return prompt;
461 }
462
463 // Otherwise let's compile the latest conversation
464 conversationToUse = conversationToUse.map(x => x.who + x.says);
465 let prompt = conversationToUse.join('\n');
466 if (casuallyFineTuned) {
467 prompt = '<?= $promptEnding ?>';
468 }
469 return prompt;
470 }
471
472 // Function to request the completion
473 function <?= $onSentClickFn ?>() {
474 let input = document.querySelector('#mwai-chat-<?= $id ?> .mwai-input textarea');
475 let inputText = input.value.trim();
476
477 // Reset the conversation if empty
478 if (inputText === '') {
479 <?= $onGoingPrompt ?> = [];
480 document.querySelector('#mwai-chat-<?= $id ?> .mwai-conversation').innerHTML = '';
481 localStorage.removeItem('mwai-chat-<?= $id ?>');
482 <?= $memorizedChat ?> = [];
483 <?= $addReplyFn ?>('<?= $startSentence ?>', 'ai');
484 return;
485 }
486
487 // Disable the button
488 var button = document.querySelector('#mwai-chat-<?= $id ?> .mwai-input button');
489 button.disabled = true;
490
491 // Add the user reply
492 <?= $addReplyFn ?>(inputText, 'user');
493 <?= $onGoingPrompt ?>.push({ who: '<?= $rawUserName ?>', says: inputText });
494 input.value = '';
495 input.setAttribute('rows', 1);
496 input.disabled = true;
497
498 // Let's build the prompt depending on the "system"
499 <?= $onGoingPrompt ?>.push({ who: '<?= $rawAiName ?>', says: '' });
500 let prompt = '<?= $context ?>' + '\n\n';
501 prompt += <?= $onTidyOnGoingPromptFn ?>(<?= $onGoingPrompt ?>, 15, <?= $casuallyFineTuned ? 1 : 0 ?>);
502
503 console.log('onGoingPrompt', <?= $onGoingPrompt ?>);
504 console.log('prompt', prompt);
505
506 // Prompt for the images
507 const data = mode === 'images' ? {
508 env: '<?= $env ?>',
509 session: '<?= $sessionId ?>',
510 prompt: inputText,
511 rawInput: inputText,
512 maxResults: <?= $maxResults ?>,
513 model: '<?= $atts['model'] ?>',
514 apiKey: '<?= $atts['api_key'] ?>',
515 // Prompt for the chat
516 } : {
517 env: '<?= $env ?>',
518 session: '<?= $sessionId ?>',
519 prompt: prompt,
520 rawInput: inputText,
521 userName: '<?= $userName ?>',
522 aiName: '<?= $aiName ?>',
523 model: '<?= $model ?>',
524 temperature: '<?= $temperature ?>',
525 maxTokens: '<?= $maxTokens ?>',
526 stop: '<?= $completionEnding ?>',
527 maxResults: 1,
528 apiKey: '<?= $apiKey ?>',
529 };
530
531 // Start the timer
532 const stopTimer = <?= $injectTimerFn ?>(button);
533
534 // Send the request
535 if (isDebugMode) {
536 console.log('[BOT] Sent: ', data);
537 }
538 fetch('<?= $apiUrl ?>', { method: 'POST', headers: {
539 'Content-Type': 'application/json',
540 'X-WP-Nonce': '<?= $rest_nonce ?>'
541 },
542 body: JSON.stringify(data)
543 })
544 .then(response => response.json())
545 .then(data => {
546 if (isDebugMode) {
547 console.log('[BOT] Recv: ', data);
548 }
549 if (!data.success) {
550 <?= $addReplyFn ?>(data.message, 'system');
551 }
552 else {
553 <?= $addReplyFn ?>(data.images ? data.images : data.html, 'ai');
554 <?= $onGoingPrompt ?>[<?= $onGoingPrompt ?>.length - 1].says = data.answer;
555 }
556 button.disabled = false;
557 input.disabled = false;
558 stopTimer();
559
560 // Only focus only on desktop (to avoid the mobile keyboard to kick-in)
561 if (!isMobile) {
562 input.focus();
563 }
564 })
565 .catch(error => {
566 console.error(error);
567 button.disabled = false;
568 input.disabled = false;
569 stopTimer();
570 });
571 }
572
573 // Keep the textarea height in sync with the content
574 function mwaiSetTextAreaHeight(textarea, lines) {
575 var rows = textarea.getAttribute('rows');
576 if (lines !== rows) {
577 textarea.setAttribute('rows', lines > 5 ? 5 : lines);
578 }
579 }
580
581 // Init the chatbot
582 function <?= $initChatBotFn ?>() {
583 var input = document.querySelector('#mwai-chat-<?= $id ?> .mwai-input textarea');
584 var button = document.querySelector('#mwai-chat-<?= $id ?> .mwai-input button');
585
586 input.addEventListener('keypress', (event) => {
587 let text = event.target.value;
588 if (event.keyCode === 13 && !text.length && !event.shiftKey) {
589 event.preventDefault();
590 return;
591 }
592 if (event.keyCode === 13 && text.length && !event.shiftKey) {
593 <?= $onSentClickFn ?>();
594 }
595 });
596 input.addEventListener('keydown', (event) => {
597 var rows = input.getAttribute('rows');
598 if (event.keyCode === 13 && event.shiftKey) {
599 var lines = input.value.split('\n').length + 1;
600 mwaiSetTextAreaHeight(input, lines);
601 }
602 });
603 input.addEventListener('keyup', (event) => {
604 var rows = input.getAttribute('rows');
605 var lines = input.value.split('\n').length ;
606 mwaiSetTextAreaHeight(input, lines);
607 <?= $setButtonTextFn ?>();
608 });
609
610 button.addEventListener('click', (event) => {
611 <?= $onSentClickFn ?>();
612 });
613
614 // If window, add event listener to mwai-open-button and mwai-close-button
615 if ( isWindow ) {
616 var openButton = document.querySelector('#mwai-chat-<?= $id ?> .mwai-open-button');
617 openButton.addEventListener('click', (event) => {
618 var chat = document.querySelector('#mwai-chat-<?= $id ?>');
619 chat.classList.add('mwai-open');
620 // Only focus only on desktop (to avoid the mobile keyboard to kick-in)
621 if (!isMobile) {
622 input.focus();
623 }
624 });
625 var closeButton = document.querySelector('#mwai-chat-<?= $id ?> .mwai-close-button');
626 closeButton.addEventListener('click', (event) => {
627 var chat = document.querySelector('#mwai-chat-<?= $id ?>');
628 chat.classList.remove('mwai-open');
629 });
630 if (isFullscreen) {
631 var resizeButton = document.querySelector('#mwai-chat-<?= $id ?> .mwai-resize-button');
632 resizeButton.addEventListener('click', (event) => {
633 var chat = document.querySelector('#mwai-chat-<?= $id ?>');
634 chat.classList.toggle('mwai-fullscreen');
635 });
636 }
637 }
638
639 // Get back the previous chat if any for the same ID
640 var chatHistory = [];
641 if (memorizeChat) {
642 chatHistory = localStorage.getItem('mwai-chat-<?= $id ?>');
643 if (chatHistory) {
644 chatHistory = JSON.parse(chatHistory);
645 chatHistory = chatHistory.filter(x => x && x.text && x.type);
646 chatHistory.forEach(x => { <?= $addReplyFn ?>(x.text, x.type) });
647 }
648 else {
649 chatHistory = [];
650 }
651 }
652 if (chatHistory.length === 0) {
653 <?= $addReplyFn ?>('<?= $startSentence ?>', 'ai');
654 }
655 }
656
657 // Let's go totally meoooow on this!
658 <?= $initChatBotFn ?>();
659 })();
660 </script>
661
662 <?php
663 $output = ob_get_contents();
664 ob_end_clean();
665 $output = apply_filters( 'mwai_chatbot', $output, $atts );
666 return $output;
667 }
668 }