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