PluginProbe ʕ •ᴥ•ʔ
AI Engine – The Chatbot, AI Framework & MCP for WordPress / 1.6.75
AI Engine – The Chatbot, AI Framework & MCP for WordPress v1.6.75
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 / core.php
ai-engine / classes Last commit date
engines 3 years ago modules 3 years ago admin.php 3 years ago api.php 3 years ago core.php 3 years ago init.php 3 years ago query.php 3 years ago queryembed.php 3 years ago queryimage.php 3 years ago querytext.php 3 years ago querytranscribe.php 3 years ago reply.php 3 years ago rest.php 3 years ago
core.php
518 lines
1 <?php
2
3 require_once( MWAI_PATH . '/vendor/autoload.php' );
4 require_once( MWAI_PATH . '/constants/init.php' );
5
6 use Rahul900day\Gpt3Encoder\Encoder;
7
8 define( 'MWAI_IMG_WAND', MWAI_URL . '/images/wand.png' );
9 define( 'MWAI_IMG_WAND_HTML', "<img style='height: 22px; margin-bottom: -5px; margin-right: 8px;'
10 src='" . MWAI_IMG_WAND . "' alt='AI Wand' />" );
11 define( 'MWAI_IMG_WAND_HTML_XS', "<img style='height: 16px; margin-bottom: -2px;'
12 src='" . MWAI_IMG_WAND . "' alt='AI Wand' />" );
13 class Meow_MWAI_Core
14 {
15 public $admin = null;
16 public $is_rest = false;
17 public $is_cli = false;
18 public $site_url = null;
19 public $ai = null;
20 private $option_name = 'mwai_options';
21 private $themes_option_name = 'mwai_themes';
22 private $chatbots_option_name = 'mwai_chatbots';
23 public $defaultChatbotParams = MWAI_CHATBOT_PARAMS;
24
25 public function __construct() {
26 $this->site_url = get_site_url();
27 $this->is_rest = MeowCommon_Helpers::is_rest();
28 $this->is_cli = defined( 'WP_CLI' );
29 $this->ai = new Meow_MWAI_Engines_Core( $this );
30 add_action( 'plugins_loaded', array( $this, 'init' ) );
31 }
32
33 function init() {
34 global $mwai;
35 $mwai = new Meow_MWAI_API();
36 new Meow_MWAI_Modules_Security( $this );
37 if ( $this->is_rest ) {
38 new Meow_MWAI_Rest( $this );
39 }
40 if ( is_admin() ) {
41 new Meow_MWAI_Admin( $this );
42 new Meow_MWAI_Modules_Assistants( $this );
43 }
44 if ( $this->get_option( 'shortcode_chat' ) ) {
45 new Meow_MWAI_Modules_Chatbot();
46 new Meow_MWAI_Modules_Chatbot_Legacy();
47 new Meow_MWAI_Modules_Discussions();
48 }
49
50 // Advanced core
51 if ( class_exists( 'MeowPro_MWAI_Core' ) ) {
52 new MeowPro_MWAI_Core( $this );
53 }
54
55 // Dynamic max tokens
56 if ( $this->get_option( 'dynamic_max_tokens' ) ) {
57 add_filter( 'mwai_estimate_tokens', array( $this, 'dynamic_max_tokens' ), 10, 2 );
58 }
59 }
60
61 #region Roles & Capabilities
62
63 function can_access_settings() {
64 return apply_filters( 'mwai_allow_setup', current_user_can( 'manage_options' ) );
65 }
66
67 function can_access_features() {
68 $editor_or_admin = current_user_can( 'editor' ) || current_user_can( 'administrator' );
69 return apply_filters( 'mwai_allow_usage', $editor_or_admin );
70 }
71
72 #endregion
73
74 #region Text-Related Helpers
75
76 // Clean the text perfectly, resolve shortcodes, etc, etc.
77 function cleanText( $rawText = "" ) {
78 $text = html_entity_decode( $rawText );
79 $text = wp_strip_all_tags( $text );
80 $text = preg_replace( '/[\r\n]+/', "\n", $text );
81 return $text . " ";
82
83 // Before simplification:
84 // $text = strip_tags( $rawText );
85 // $text = strip_shortcodes( $text );
86 // $text = html_entity_decode( $text );
87 // $text = preg_replace( '/[\r\n]+/', "\n", $text );
88 // $sentences = preg_split( '/(?<=[.?!])(?=[a-zA-Z ])/', $text );
89 // foreach ( $sentences as $key => $sentence ) {
90 // $sentences[$key] = trim( $sentence );
91 // }
92 // $text = implode( " ", $sentences );
93 // $text = preg_replace( '/^[\pZ\pC]+|[\pZ\pC]+$/u', '', $text );
94 // return $text . " ";
95 }
96
97 // Make sure there are no duplicate sentences, and keep the length under a maximum length.
98 function cleanSentences( $text, $maxTokens = null ) {
99 //$sentences = preg_split( '/(?<=[.?!])(?=[a-zA-Z ])/', $text );
100 $maxTokens = $maxTokens ? $maxTokens : $this->get_option( 'context_max_tokens', 1024 );
101 $sentences = preg_split('/(?<=[.?!。.!?])+/u', $text);
102 $hashes = array();
103 $uniqueSentences = array();
104 $length = 0;
105 foreach ( $sentences as $sentence ) {
106 $sentence = preg_replace( '/^[\pZ\pC]+|[\pZ\pC]+$/u', '', $sentence );
107 $hash = md5( $sentence );
108 if ( !in_array( $hash, $hashes ) ) {
109 $tokensCount = apply_filters( 'mwai_estimate_tokens', 0, $sentence );
110 if ( $length + $tokensCount > $maxTokens ) {
111 continue;
112 }
113 $hashes[] = $hash;
114 $uniqueSentences[] = $sentence;
115 $length += $tokensCount;
116 }
117 }
118 $freshText = implode( " ", $uniqueSentences );
119 $freshText = preg_replace( '/^[\pZ\pC]+|[\pZ\pC]+$/u', '', $freshText );
120 return $freshText;
121 }
122
123 function getCleanPostContent( $postId ) {
124 $post = get_post( $postId );
125 if ( !$post ) {
126 return false;
127 }
128 $text = $post->post_content;
129 $pattern = '/\[mwai_.*?\]/';
130 $text = preg_replace( $pattern, '', $text );
131 if ( $this->get_option( 'resolve_shortcodes' ) ) {
132 $text = apply_filters( 'the_content', $text );
133 }
134 $text = $this->cleanText( $text );
135 $text = $this->cleanSentences( $text );
136 return $text;
137 }
138
139 function markdown_to_html( $content ) {
140 $Parsedown = new Parsedown();
141 $content = $Parsedown->text( $content );
142 return $content;
143 }
144
145 function get_post_language( $postId ) {
146 $locale = get_locale();
147 $code = strtolower( substr( $locale, 0, 2 ) );
148 $humanLanguage = strtr( $code, MWAI_ALL_LANGUAGES );
149 $lang = apply_filters( 'wpml_post_language_details', null, $postId );
150 if ( !empty( $lang ) ) {
151 $locale = $lang['locale'];
152 $humanLanguage = $lang['display_name'];
153 }
154 return strtolower( "$locale ($humanLanguage)" );
155 }
156 #endregion
157
158 #region Users/Sessions Helpers
159
160 function get_session_id() {
161 if ( isset( $_COOKIE['mwai_session_id'] ) ) {
162 return $_COOKIE['mwai_session_id'];
163 }
164 return "N/A";
165 }
166
167 // Get the UserID from the data, or from the current user
168 function get_user_id( $data = null ) {
169 if ( isset( $data ) && isset( $data['userId'] ) ) {
170 return (int)$data['userId'];
171 }
172 if ( is_user_logged_in() ) {
173 $current_user = wp_get_current_user();
174 if ( $current_user->ID > 0 ) {
175 return $current_user->ID;
176 }
177 }
178 return null;
179 }
180
181 function getUserData() {
182 $user = wp_get_current_user();
183 if ( empty( $user ) || empty( $user->ID ) ) {
184 return null;
185 }
186 $placeholders = array(
187 'FIRST_NAME' => get_user_meta( $user->ID, 'first_name', true ),
188 'LAST_NAME' => get_user_meta( $user->ID, 'last_name', true ),
189 'USER_LOGIN' => isset( $user ) && isset($user->data) && isset( $user->data->user_login ) ?
190 $user->data->user_login : null,
191 'DISPLAY_NAME' => isset( $user ) && isset( $user->data ) && isset( $user->data->display_name ) ?
192 $user->data->display_name : null,
193 'AVATAR_URL' => get_avatar_url( get_current_user_id() ),
194 );
195 return $placeholders;
196 }
197
198 function get_ip_address( $data = null ) {
199 if ( isset( $data ) && isset( $data['ip'] ) ) {
200 $data['ip'] = (string)$data['ip'];
201 }
202 else {
203 if ( isset( $_SERVER['REMOTE_ADDR'] ) ) {
204 $data['ip'] = sanitize_text_field( $_SERVER['REMOTE_ADDR'] );
205 }
206 else if ( isset( $_SERVER['HTTP_CLIENT_IP'] ) ) {
207 $data['ip'] = sanitize_text_field( $_SERVER['HTTP_CLIENT_IP'] );
208 }
209 else if ( isset( $_SERVER['HTTP_X_FORWARDED_ FOR'] ) ) {
210 $data['ip'] = sanitize_text_field( $_SERVER['HTTP_X_FORWARDED_FOR'] );
211 }
212 }
213 $ip = apply_filters( 'mwai_get_ip_address', $data['ip'] );
214 return $ip;
215 }
216
217 #endregion
218
219 #region Other Helpers
220
221 function isUrl( $url ) {
222 return strpos( $url, 'http' ) === 0 ? true : false;
223 }
224
225 function getPostTypes() {
226 $excluded = array( 'attachment', 'revision', 'nav_menu_item' );
227 $post_types = array();
228 $types = get_post_types( array( 'public' => true ), 'objects' );
229 foreach ( $types as $type ) {
230 if ( in_array( $type->name, $excluded ) ) {
231 continue;
232 }
233 $post_types[] = array(
234 'name' => $type->labels->name,
235 'type' => $type->name,
236 );
237 }
238 return $post_types;
239 }
240
241 function getCleanPost( $post ) {
242 if ( is_object( $post ) ) {
243 $post = (array)$post;
244 }
245 $language = $this->get_post_language( $post['ID'] );
246 $content = apply_filters( 'mwai_pre_post_content', $post['post_content'], $post['ID'] );
247 $content = $this->cleanText( $content );
248 $content = apply_filters( 'mwai_post_content', $content, $post['ID'] );
249 $title = $post['post_title'];
250 $excerpt = $post['post_excerpt'];
251 $url = get_permalink( $post['ID'] );
252 $checksum = wp_hash( $content . $title . $url );
253 return [
254 'postId' => $post['ID'],
255 'title' => $title,
256 'content' => $content,
257 'excerpt' => $excerpt,
258 'url' => $url,
259 'language' => $language,
260 'checksum' => $checksum,
261 ];
262 }
263
264 #endregion
265
266 #region Usage & Costs
267
268 public function dynamic_max_tokens( $tokens, $text ) {
269 // Approximation (fast, no lib)
270 $asciiCount = 0;
271 $nonAsciiCount = 0;
272 for ( $i = 0; $i < mb_strlen( $text ); $i++ ) {
273 $char = mb_substr( $text, $i, 1 );
274 if ( ord( $char ) < 128 ) {
275 $asciiCount++;
276 }
277 else {
278 $nonAsciiCount++;
279 }
280 }
281 $asciiTokens = $asciiCount / 3.5;
282 $nonAsciiTokens = $nonAsciiCount * 2.5;
283 $tokens = $asciiTokens + $nonAsciiTokens;
284
285 // More exact (slower, and lib)
286 if ( PHP_VERSION_ID >= 70400 && function_exists( 'mb_convert_encoding' ) ) {
287 try {
288 $token_array = Encoder::encode( $text );
289 if ( !empty( $token_array ) ) {
290 $tokens = count( $token_array );
291 }
292 }
293 catch ( Exception $e ) {
294 error_log( $e->getMessage() );
295 }
296 }
297
298 $tokens = $tokens;
299 return (int)$tokens;
300 }
301
302 public function recordTokensUsage( $model, $prompt_tokens, $completion_tokens = 0 ) {
303 if ( !is_numeric( $prompt_tokens ) ) {
304 throw new Exception( 'Record usage: prompt_tokens is not a number.' );
305 }
306 if ( !is_numeric( $completion_tokens ) ) {
307 $completion_tokens = 0;
308 }
309 if ( !$model ) {
310 throw new Exception( 'Record usage: model is missing.' );
311 }
312 $usage = $this->get_option( 'openai_usage' );
313 $month = date( 'Y-m' );
314 if ( !isset( $usage[$month] ) ) {
315 $usage[$month] = array();
316 }
317 if ( !isset( $usage[$month][$model] ) ) {
318 $usage[$month][$model] = array(
319 'prompt_tokens' => 0,
320 'completion_tokens' => 0,
321 'total_tokens' => 0
322 );
323 }
324 $usage[$month][$model]['prompt_tokens'] += $prompt_tokens;
325 $usage[$month][$model]['completion_tokens'] += $completion_tokens;
326 $usage[$month][$model]['total_tokens'] += $prompt_tokens + $completion_tokens;
327 $this->update_option( 'openai_usage', $usage );
328 return [
329 'prompt_tokens' => $prompt_tokens,
330 'completion_tokens' => $completion_tokens,
331 'total_tokens' => $prompt_tokens + $completion_tokens
332 ];
333 }
334
335 public function recordAudioUsage( $model, $seconds ) {
336 if ( !is_numeric( $seconds ) ) {
337 throw new Exception( 'Record usage: seconds is not a number.' );
338 }
339 if ( !$model ) {
340 throw new Exception( 'Record usage: model is missing.' );
341 }
342 $usage = $this->get_option( 'openai_usage' );
343 $month = date( 'Y-m' );
344 if ( !isset( $usage[$month] ) ) {
345 $usage[$month] = array();
346 }
347 if ( !isset( $usage[$month][$model] ) ) {
348 $usage[$month][$model] = array(
349 'seconds' => 0
350 );
351 }
352 $usage[$month][$model]['seconds'] += $seconds;
353 $this->update_option( 'openai_usage', $usage );
354 return [
355 'seconds' => $seconds
356 ];
357 }
358
359 public function recordImagesUsage( $model, $resolution, $images ) {
360 if ( !$model || !$resolution || !$images ) {
361 throw new Exception( 'Missing parameters for record_image_usage.' );
362 }
363 $usage = $this->get_option( 'openai_usage' );
364 $month = date( 'Y-m' );
365 if ( !isset( $usage[$month] ) ) {
366 $usage[$month] = array();
367 }
368 if ( !isset( $usage[$month][$model] ) ) {
369 $usage[$month][$model] = array(
370 'resolution' => array(),
371 'images' => 0
372 );
373 }
374 if ( !isset( $usage[$month][$model]['resolution'][$resolution] ) ) {
375 $usage[$month][$model]['resolution'][$resolution] = 0;
376 }
377 $usage[$month][$model]['resolution'][$resolution] += $images;
378 $usage[$month][$model]['images'] += $images;
379 $this->update_option( 'openai_usage', $usage );
380 return [
381 'resolution' => $resolution,
382 'images' => $images
383 ];
384 }
385
386 #endregion
387
388 #region Options
389 function getThemes()
390 {
391 $themes = get_option( $this->themes_option_name, [] );
392 $themes = empty( $themes ) ? [] : $themes;
393
394 $internalThemes = [
395 'chatgpt' => [
396 'type' => 'internal', 'name' => 'ChatGPT', 'themeId' => 'chatgpt',
397 'settings' => [], 'style' => ""
398 ],
399 'messages' => [
400 'type' => 'internal', 'name' => 'Messages', 'themeId' => 'messages',
401 'settings' => [], 'style' => ""
402 ],
403 ];
404 $customThemes = [];
405 foreach ( $themes as $theme ) {
406 if ( isset( $internalThemes[$theme['themeId']] ) ) {
407 $internalThemes[$theme['themeId']] = $theme;
408 continue;
409 }
410 $customThemes[] = $theme;
411 }
412 return array_merge(array_values($internalThemes), $customThemes);
413 }
414
415 function updateThemes( $themes ) {
416 update_option( $this->themes_option_name, $themes );
417 return $themes;
418 }
419
420 function getChatbots() {
421 $chatbots = get_option( $this->chatbots_option_name, [] );
422 if ( empty( $chatbots ) ) {
423 $chatbots = [ array_merge( MWAI_CHATBOT_DEFAULT_PARAMS, ['name' => 'Default', 'chatId' => 'default' ] ) ];
424 }
425 foreach ( $chatbots as &$chatbot ) {
426 foreach ( MWAI_CHATBOT_DEFAULT_PARAMS as $key => $value ) {
427 if ( !isset( $chatbot[$key] ) ) {
428 $chatbot[$key] = $value;
429 }
430 }
431 }
432 return $chatbots;
433 }
434
435 function getChatbot( $chatId ) {
436 $chatbots = $this->getChatbots();
437 foreach ( $chatbots as $chatbot ) {
438 if ( $chatbot['chatId'] === (string)$chatId ) {
439 // Somehow, the default was set to "openai" when creating a new chatbot, but that overrided
440 // the default value in the Settings. It should be always empty here (except if we add this
441 // into the Settings of the chatbot).
442 $chatbot['service'] = null;
443 return $chatbot;
444 }
445 }
446 return null;
447 }
448
449 function getTheme( $themeId ) {
450 $themes = $this->getThemes();
451 foreach ( $themes as $theme ) {
452 if ( $theme['themeId'] === $themeId ) {
453 return $theme;
454 }
455 }
456 return null;
457 }
458
459 function updateChatbots( $chatbots ) {
460 update_option( $this->chatbots_option_name, $chatbots );
461 return $chatbots;
462 }
463
464 function get_all_options() {
465 $options = get_option( $this->option_name, null );
466 foreach ( MWAI_OPTIONS as $key => $value ) {
467 if ( !isset( $options[$key] ) ) {
468 $options[$key] = $value;
469 }
470 if ( $key === 'languages' ) {
471 // NOTE: If we decide to make a set of options for languages, we can keep it in the settings
472 $options[$key] = MWAI_LANGUAGES;
473 $options[$key] = apply_filters( 'mwai_languages', $options[$key] );
474 }
475 }
476 $options['shortcode_chat_default_params'] = MWAI_CHATBOT_PARAMS;
477 $options['chatbot_defaults'] = MWAI_CHATBOT_DEFAULT_PARAMS;
478 $options['default_limits'] = MWAI_LIMITS;
479 $options['openai_models'] = MWAI_OPENAI_MODELS;
480 return $options;
481 }
482
483 // Validate and keep the options clean and logical.
484 function sanitize_options() {
485 $options = $this->get_all_options();
486 $needs_update = false;
487
488 // We can sanitize our future options here, let's always remember it.
489 // Now, it is empty...
490
491 if ( $needs_update ) {
492 update_option( $this->option_name, $options, false );
493 }
494 return $options;
495 }
496
497 function update_options( $options ) {
498 if ( !update_option( $this->option_name, $options, false ) ) {
499 return false;
500 }
501 $options = $this->sanitize_options();
502 return $options;
503 }
504
505 function update_option( $option, $value ) {
506 $options = $this->get_all_options();
507 $options[$option] = $value;
508 return $this->update_options( $options );
509 }
510
511 function get_option( $option, $default = null ) {
512 $options = $this->get_all_options();
513 return $options[$option] ?? $default;
514 }
515 #endregion
516 }
517
518 ?>