PluginProbe ʕ •ᴥ•ʔ
AI Engine – The Chatbot, AI Framework & MCP for WordPress / 1.3.98
AI Engine – The Chatbot, AI Framework & MCP for WordPress v1.3.98
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
modules 3 years ago admin.php 3 years ago ai.php 3 years ago answer.php 3 years ago api.php 3 years ago core.php 3 years ago init.php 3 years ago openai.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 rest.php 3 years ago security.php 3 years ago ui.php 3 years ago
core.php
627 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' ) && WP_CLI;
29 $this->ai = new Meow_MWAI_AI( $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_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 else {
45 //new Meow_MWAI_UI( $this );
46 if ( $this->get_option( 'shortcode_chat' ) ) {
47 new Meow_MWAI_Modules_Chatbot();
48 }
49 }
50
51 // Advanced core
52 if ( class_exists( 'MeowPro_MWAI_Core' ) ) {
53 new MeowPro_MWAI_Core( $this );
54 }
55
56 // Dynamic max tokens
57 if ( $this->get_option( 'dynamic_max_tokens' ) ) {
58 add_filter( 'mwai_estimate_tokens', array( $this, 'dynamic_max_tokens' ), 10, 2 );
59 }
60 }
61
62 #region Roles & Capabilities
63
64 function can_access_settings() {
65 return apply_filters( 'mwai_allow_setup', current_user_can( 'manage_options' ) );
66 }
67
68 function can_access_features() {
69 $editor_or_admin = current_user_can( 'editor' ) || current_user_can( 'administrator' );
70 return apply_filters( 'mwai_allow_usage', $editor_or_admin );
71 }
72
73 #endregion
74
75 #region Text-Related Helpers
76
77 // Clean the text perfectly, resolve shortcodes, etc, etc.
78 function cleanText( $rawText = "" ) {
79 $text = html_entity_decode( $rawText );
80 $text = wp_strip_all_tags( $text );
81 $text = preg_replace( '/[\r\n]+/', "\n", $text );
82 return $text . " ";
83
84 // Before simplification:
85 // $text = strip_tags( $rawText );
86 // $text = strip_shortcodes( $text );
87 // $text = html_entity_decode( $text );
88 // $text = preg_replace( '/[\r\n]+/', "\n", $text );
89 // $sentences = preg_split( '/(?<=[.?!])(?=[a-zA-Z ])/', $text );
90 // foreach ( $sentences as $key => $sentence ) {
91 // $sentences[$key] = trim( $sentence );
92 // }
93 // $text = implode( " ", $sentences );
94 // $text = preg_replace( '/^[\pZ\pC]+|[\pZ\pC]+$/u', '', $text );
95 // return $text . " ";
96 }
97
98 // Make sure there are no duplicate sentences, and keep the length under a maximum length.
99 function cleanSentences( $text, $maxTokens = 512 ) {
100 //$sentences = preg_split( '/(?<=[.?!])(?=[a-zA-Z ])/', $text );
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 $post->post_content = apply_filters( 'the_content', $post->post_content );
129 $text = $this->cleanText( $post->post_content );
130 $text = $this->cleanSentences( $text );
131 return $text;
132 }
133
134 function markdown_to_html( $content ) {
135 $Parsedown = new Parsedown();
136 $content = $Parsedown->text( $content );
137 return $content;
138 }
139
140 function get_post_language( $postId ) {
141 $locale = get_locale();
142 $code = strtolower( substr( $locale, 0, 2 ) );
143 $lang_codes = array(
144 'aa' => 'Afar',
145 'ab' => 'Abkhazian',
146 'af' => 'Afrikaans',
147 'ak' => 'Akan',
148 'sq' => 'Albanian',
149 'am' => 'Amharic',
150 'ar' => 'Arabic',
151 'an' => 'Aragonese',
152 'hy' => 'Armenian',
153 'as' => 'Assamese',
154 'av' => 'Avaric',
155 'ae' => 'Avestan',
156 'ay' => 'Aymara',
157 'az' => 'Azerbaijani',
158 'ba' => 'Bashkir',
159 'bm' => 'Bambara',
160 'eu' => 'Basque',
161 'be' => 'Belarusian',
162 'bn' => 'Bengali',
163 'bh' => 'Bihari',
164 'bi' => 'Bislama',
165 'bs' => 'Bosnian',
166 'br' => 'Breton',
167 'bg' => 'Bulgarian',
168 'my' => 'Burmese',
169 'ca' => 'Catalan; Valencian',
170 'ch' => 'Chamorro',
171 'ce' => 'Chechen',
172 'zh' => 'Chinese',
173 'cu' => 'Church Slavic; Old Slavonic; Church Slavonic; Old Bulgarian; Old Church Slavonic',
174 'cv' => 'Chuvash',
175 'kw' => 'Cornish',
176 'co' => 'Corsican',
177 'cr' => 'Cree',
178 'cs' => 'Czech',
179 'da' => 'Danish',
180 'dv' => 'Divehi; Dhivehi; Maldivian',
181 'nl' => 'Dutch; Flemish',
182 'dz' => 'Dzongkha',
183 'en' => 'English',
184 'eo' => 'Esperanto',
185 'et' => 'Estonian',
186 'ee' => 'Ewe',
187 'fo' => 'Faroese',
188 'fj' => 'Fijjian',
189 'fi' => 'Finnish',
190 'fr' => 'French',
191 'fy' => 'Western Frisian',
192 'ff' => 'Fulah',
193 'ka' => 'Georgian',
194 'de' => 'German',
195 'gd' => 'Gaelic; Scottish Gaelic',
196 'ga' => 'Irish',
197 'gl' => 'Galician',
198 'gv' => 'Manx',
199 'el' => 'Greek, Modern',
200 'gn' => 'Guarani',
201 'gu' => 'Gujarati',
202 'ht' => 'Haitian; Haitian Creole',
203 'ha' => 'Hausa',
204 'he' => 'Hebrew',
205 'hz' => 'Herero',
206 'hi' => 'Hindi',
207 'ho' => 'Hiri Motu',
208 'hu' => 'Hungarian',
209 'ig' => 'Igbo',
210 'is' => 'Icelandic',
211 'io' => 'Ido',
212 'ii' => 'Sichuan Yi',
213 'iu' => 'Inuktitut',
214 'ie' => 'Interlingue',
215 'ia' => 'Interlingua (International Auxiliary Language Association)',
216 'id' => 'Indonesian',
217 'ik' => 'Inupiaq',
218 'it' => 'Italian',
219 'jv' => 'Javanese',
220 'ja' => 'Japanese',
221 'kl' => 'Kalaallisut; Greenlandic',
222 'kn' => 'Kannada',
223 'ks' => 'Kashmiri',
224 'kr' => 'Kanuri',
225 'kk' => 'Kazakh',
226 'km' => 'Central Khmer',
227 'ki' => 'Kikuyu; Gikuyu',
228 'rw' => 'Kinyarwanda',
229 'ky' => 'Kirghiz; Kyrgyz',
230 'kv' => 'Komi',
231 'kg' => 'Kongo',
232 'ko' => 'Korean',
233 'kj' => 'Kuanyama; Kwanyama',
234 'ku' => 'Kurdish',
235 'lo' => 'Lao',
236 'la' => 'Latin',
237 'lv' => 'Latvian',
238 'li' => 'Limburgan; Limburger; Limburgish',
239 'ln' => 'Lingala',
240 'lt' => 'Lithuanian',
241 'lb' => 'Luxembourgish; Letzeburgesch',
242 'lu' => 'Luba-Katanga',
243 'lg' => 'Ganda',
244 'mk' => 'Macedonian',
245 'mh' => 'Marshallese',
246 'ml' => 'Malayalam',
247 'mi' => 'Maori',
248 'mr' => 'Marathi',
249 'ms' => 'Malay',
250 'mg' => 'Malagasy',
251 'mt' => 'Maltese',
252 'mo' => 'Moldavian',
253 'mn' => 'Mongolian',
254 'na' => 'Nauru',
255 'nv' => 'Navajo; Navaho',
256 'nr' => 'Ndebele, South; South Ndebele',
257 'nd' => 'Ndebele, North; North Ndebele',
258 'ng' => 'Ndonga',
259 'ne' => 'Nepali',
260 'nn' => 'Norwegian Nynorsk; Nynorsk, Norwegian',
261 'nb' => 'Bokmål, Norwegian, Norwegian Bokmål',
262 'no' => 'Norwegian',
263 'ny' => 'Chichewa; Chewa; Nyanja',
264 'oc' => 'Occitan, Provençal',
265 'oj' => 'Ojibwa',
266 'or' => 'Oriya',
267 'om' => 'Oromo',
268 'os' => 'Ossetian; Ossetic',
269 'pa' => 'Panjabi; Punjabi',
270 'fa' => 'Persian',
271 'pi' => 'Pali',
272 'pl' => 'Polish',
273 'pt' => 'Portuguese',
274 'ps' => 'Pushto',
275 'qu' => 'Quechua',
276 'rm' => 'Romansh',
277 'ro' => 'Romanian',
278 'rn' => 'Rundi',
279 'ru' => 'Russian',
280 'sg' => 'Sango',
281 'sa' => 'Sanskrit',
282 'sr' => 'Serbian',
283 'hr' => 'Croatian',
284 'si' => 'Sinhala; Sinhalese',
285 'sk' => 'Slovak',
286 'sl' => 'Slovenian',
287 'se' => 'Northern Sami',
288 'sm' => 'Samoan',
289 'sn' => 'Shona',
290 'sd' => 'Sindhi',
291 'so' => 'Somali',
292 'st' => 'Sotho, Southern',
293 'es' => 'Spanish; Castilian',
294 'sc' => 'Sardinian',
295 'ss' => 'Swati',
296 'su' => 'Sundanese',
297 'sw' => 'Swahili',
298 'sv' => 'Swedish',
299 'ty' => 'Tahitian',
300 'ta' => 'Tamil',
301 'tt' => 'Tatar',
302 'te' => 'Telugu',
303 'tg' => 'Tajik',
304 'tl' => 'Tagalog',
305 'th' => 'Thai',
306 'bo' => 'Tibetan',
307 'ti' => 'Tigrinya',
308 'to' => 'Tonga (Tonga Islands)',
309 'tn' => 'Tswana',
310 'ts' => 'Tsonga',
311 'tk' => 'Turkmen',
312 'tr' => 'Turkish',
313 'tw' => 'Twi',
314 'ug' => 'Uighur; Uyghur',
315 'uk' => 'Ukrainian',
316 'ur' => 'Urdu',
317 'uz' => 'Uzbek',
318 've' => 'Venda',
319 'vi' => 'Vietnamese',
320 'vo' => 'Volapük',
321 'cy' => 'Welsh',
322 'wa' => 'Walloon',
323 'wo' => 'Wolof',
324 'xh' => 'Xhosa',
325 'yi' => 'Yiddish',
326 'yo' => 'Yoruba',
327 'za' => 'Zhuang; Chuang',
328 'zu' => 'Zulu',
329 );
330 $humanLanguage = strtr( $code, $lang_codes );
331 $lang = apply_filters( 'wpml_post_language_details', null, $postId );
332 if ( !empty( $lang ) ) {
333 $locale = $lang['locale'];
334 $humanLanguage = $lang['display_name'];
335 }
336 return strtolower( "$locale ($humanLanguage)" );
337 }
338 #endregion
339
340 #region Users/Sessions Helpers
341
342 function get_session_id() {
343 if ( isset( $_COOKIE['mwai_session_id'] ) ) {
344 return $_COOKIE['mwai_session_id'];
345 }
346 return "N/A";
347 }
348
349 // Get the UserID from the data, or from the current user
350 function get_user_id( $data = null ) {
351 if ( isset( $data ) && isset( $data['userId'] ) ) {
352 return (int)$data['userId'];
353 }
354 if ( is_user_logged_in() ) {
355 $current_user = wp_get_current_user();
356 if ( $current_user->ID > 0 ) {
357 return $current_user->ID;
358 }
359 }
360 return null;
361 }
362
363 function getUserData() {
364 $user = wp_get_current_user();
365 $placeholders = array(
366 'FIRST_NAME' => get_user_meta($user->ID, 'first_name', true),
367 'LAST_NAME' => get_user_meta($user->ID, 'last_name', true),
368 'USER_LOGIN' => $user->data->user_login,
369 'DISPLAY_NAME' => $user->data->display_name,
370 'AVATAR_URL' => get_avatar_url( get_current_user_id() ),
371 );
372 return $placeholders;
373 }
374
375 function get_ip_address( $data = null ) {
376 if ( isset( $data ) && isset( $data['ip'] ) ) {
377 $data['ip'] = (string)$data['ip'];
378 }
379 else {
380 if ( isset( $_SERVER['REMOTE_ADDR'] ) ) {
381 $data['ip'] = sanitize_text_field( $_SERVER['REMOTE_ADDR'] );
382 }
383 else if ( isset( $_SERVER['HTTP_CLIENT_IP'] ) ) {
384 $data['ip'] = sanitize_text_field( $_SERVER['HTTP_CLIENT_IP'] );
385 }
386 else if ( isset( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) {
387 $data['ip'] = sanitize_text_field( $_SERVER['HTTP_X_FORWARDED_FOR'] );
388 }
389 }
390 return $data['ip'];
391 }
392
393 #endregion
394
395 #region Other Helpers
396
397 function isUrl( $url ) {
398 return strpos( $url, 'http' ) === 0 ? true : false;
399 }
400
401 function getPostTypes() {
402 $excluded = array( 'attachment', 'revision', 'nav_menu_item' );
403 $post_types = array();
404 $types = get_post_types( array( 'public' => true ), 'objects' );
405 foreach ( $types as $type ) {
406 if ( in_array( $type->name, $excluded ) ) {
407 continue;
408 }
409 $post_types[] = array(
410 'name' => $type->labels->name,
411 'type' => $type->name,
412 );
413 }
414 return $post_types;
415 }
416
417 function getCleanPost( $post ) {
418 if ( is_object( $post ) ) {
419 $post = (array)$post;
420 }
421 $language = $this->get_post_language( $post['ID'] );
422 $content = apply_filters( 'mwai_pre_post_content', $post['post_content'], $post['ID'] );
423 $content = $this->cleanText( $content );
424 $content = apply_filters( 'mwai_post_content', $content, $post['ID'] );
425 $title = $post['post_title'];
426 $excerpt = $post['post_excerpt'];
427 $url = get_permalink( $post['ID'] );
428 $checksum = wp_hash( $content . $title . $url );
429 return [
430 'postId' => $post['ID'],
431 'title' => $title,
432 'content' => $content,
433 'excerpt' => $excerpt,
434 'url' => $url,
435 'language' => $language,
436 'checksum' => $checksum,
437 ];
438 }
439
440 #endregion
441
442 #region Usage & Costs
443
444 public function dynamic_max_tokens( $tokens, $text ) {
445 // Approximation (fast, no lib)
446 $asciiCount = 0;
447 $nonAsciiCount = 0;
448 for ( $i = 0; $i < mb_strlen( $text ); $i++ ) {
449 $char = mb_substr( $text, $i, 1 );
450 if ( ord( $char ) < 128 ) {
451 $asciiCount++;
452 }
453 else {
454 $nonAsciiCount++;
455 }
456 }
457 $asciiTokens = $asciiCount / 3.5;
458 $nonAsciiTokens = $nonAsciiCount * 2.5;
459 $tokens = $asciiTokens + $nonAsciiTokens;
460
461 // More exact (slower, and lib)
462 if ( PHP_VERSION_ID >= 70400 && function_exists( 'mb_convert_encoding' ) ) {
463 try {
464 $token_array = Encoder::encode( $text );
465 if ( !empty( $token_array ) ) {
466 $tokens = count( $token_array );
467 }
468 }
469 catch ( Exception $e ) {
470 error_log( $e->getMessage() );
471 }
472 }
473
474 $tokens = $tokens;
475 return (int)$tokens;
476 }
477
478 public function record_tokens_usage( $model, $prompt_tokens, $completion_tokens = 0 ) {
479 if ( !is_numeric( $prompt_tokens ) ) {
480 throw new Exception( 'Record usage: prompt_tokens is not a number.' );
481 }
482 if ( !is_numeric( $completion_tokens ) ) {
483 $completion_tokens = 0;
484 }
485 if ( !$model ) {
486 throw new Exception( 'Record usage: model is missing.' );
487 }
488 $usage = $this->get_option( 'openai_usage' );
489 $month = date( 'Y-m' );
490 if ( !isset( $usage[$month] ) ) {
491 $usage[$month] = array();
492 }
493 if ( !isset( $usage[$month][$model] ) ) {
494 $usage[$month][$model] = array(
495 'prompt_tokens' => 0,
496 'completion_tokens' => 0,
497 'total_tokens' => 0
498 );
499 }
500 $usage[$month][$model]['prompt_tokens'] += $prompt_tokens;
501 $usage[$month][$model]['completion_tokens'] += $completion_tokens;
502 $usage[$month][$model]['total_tokens'] += $prompt_tokens + $completion_tokens;
503 $this->update_option( 'openai_usage', $usage );
504 return [
505 'prompt_tokens' => $prompt_tokens,
506 'completion_tokens' => $completion_tokens,
507 'total_tokens' => $prompt_tokens + $completion_tokens
508 ];
509 }
510
511 public function record_images_usage( $model, $resolution, $images ) {
512 if ( !$model || !$resolution || !$images ) {
513 throw new Exception( 'Missing parameters for record_image_usage.' );
514 }
515 $usage = $this->get_option( 'openai_usage' );
516 $month = date( 'Y-m' );
517 if ( !isset( $usage[$month] ) ) {
518 $usage[$month] = array();
519 }
520 if ( !isset( $usage[$month][$model] ) ) {
521 $usage[$month][$model] = array(
522 'resolution' => array(),
523 'images' => 0
524 );
525 }
526 if ( !isset( $usage[$month][$model]['resolution'][$resolution] ) ) {
527 $usage[$month][$model]['resolution'][$resolution] = 0;
528 }
529 $usage[$month][$model]['resolution'][$resolution] += $images;
530 $usage[$month][$model]['images'] += $images;
531 $this->update_option( 'openai_usage', $usage );
532 return [
533 'resolution' => $resolution,
534 'images' => $images
535 ];
536 }
537
538 #endregion
539
540 #region Options
541 function getThemes() {
542 $themes = get_option( $this->themes_option_name, [
543 'theme' => 'chatgpt',
544 'params' => [],
545 'style' => ""
546 ] );
547 return $themes;
548 }
549
550 function updateThemes( $themes ) {
551 update_option( $this->themes_option_name, $themes );
552 }
553
554 function getChatbots() {
555 $chatbots = get_option( $this->chatbots_option_name, [] );
556 if ( empty( $chatbots ) ) {
557 $chatbots = [ array_merge( MWAI_CHATBOT_PARAMS, ['name' => 'Default', 'chatId' => 'default' ] ) ];
558 }
559 foreach ( $chatbots as $chatbot ) {
560 foreach ( MWAI_CHATBOT_PARAMS as $key => $value ) {
561 if ( !isset( $chatbot[$key] ) ) {
562 $chatbot[$key] = $value;
563 }
564 }
565 }
566 return $chatbots;
567 }
568
569 function updateChatbots( $chatbots ) {
570 update_option( $this->chatbots_option_name, $chatbots );
571 return $chatbots;
572 }
573
574 function get_all_options() {
575 $options = get_option( $this->option_name, null );
576 foreach ( MWAI_OPTIONS as $key => $value ) {
577 if ( !isset( $options[$key] ) ) {
578 $options[$key] = $value;
579 }
580 if ( $key === 'languages' ) {
581 // TODO: If we decide to make a set of options for languages, we can keep it in the settings
582 $options[$key] = MWAI_LANGUAGES;
583 $options[$key] = apply_filters( 'mwai_languages', $options[$key] );
584 }
585 }
586 $options['shortcode_chat_default_params'] = MWAI_CHATBOT_PARAMS;
587 $options['default_limits'] = MWAI_LIMITS;
588 $options['openai_models'] = MWAI_OPENAI_MODELS;
589 return $options;
590 }
591
592 // Validate and keep the options clean and logical.
593 function sanitize_options() {
594 $options = $this->get_all_options();
595 $needs_update = false;
596
597 // We can sanitize our future options here, let's always remember it.
598 // Now, it is empty...
599
600 if ( $needs_update ) {
601 update_option( $this->option_name, $options, false );
602 }
603 return $options;
604 }
605
606 function update_options( $options ) {
607 if ( !update_option( $this->option_name, $options, false ) ) {
608 return false;
609 }
610 $options = $this->sanitize_options();
611 return $options;
612 }
613
614 function update_option( $option, $value ) {
615 $options = $this->get_all_options();
616 $options[$option] = $value;
617 return $this->update_options( $options );
618 }
619
620 function get_option( $option, $default = null ) {
621 $options = $this->get_all_options();
622 return $options[$option] ?? $default;
623 }
624 #endregion
625 }
626
627 ?>